mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 12:04:41 +01:00
fix(runtime): preserve merge resolutions after rebase
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
26bc68becd
commit
6d6c4ddf15
5 files changed
+67
-31
No files matched your search
@@ -1,3 +1,3 @@
|
||||
ALTER TABLE "workspace_runtime_services" ADD COLUMN "exposure" jsonb;
|
||||
ALTER TABLE "workspace_runtime_services" ADD COLUMN "exposure_handle" text;
|
||||
ALTER TABLE "workspace_runtime_services" ADD COLUMN "backend_url" text;
|
||||
ALTER TABLE "workspace_runtime_services" ADD COLUMN IF NOT EXISTS "exposure" jsonb;
|
||||
ALTER TABLE "workspace_runtime_services" ADD COLUMN IF NOT EXISTS "exposure_handle" text;
|
||||
ALTER TABLE "workspace_runtime_services" ADD COLUMN IF NOT EXISTS "backend_url" text;
|
||||
Generated
-12
@@ -714,18 +714,6 @@ importers:
|
||||
specifier: ^22.20.1
|
||||
version: 22.20.1
|
||||
|
||||
packages/tailscale-https-broker:
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^22.20.1
|
||||
version: 22.20.1
|
||||
typescript:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
vitest:
|
||||
specifier: ^4.1.10
|
||||
version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@22.20.1)(jsdom@28.1.0(@noble/hashes@2.2.0))(vite@7.3.1(@types/node@22.20.1)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.1))
|
||||
|
||||
packages/teams-catalog:
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
|
||||
@@ -96,13 +96,15 @@ if (optedIn && !live) {
|
||||
// An ephemeral legacy port rather than the real template's 45439, so this
|
||||
// never contends with the live workspace runtime on the same host.
|
||||
const reservePort = async () => {
|
||||
const probe = net.createServer();
|
||||
await new Promise<void>((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
||||
const address = probe.address();
|
||||
const port = typeof address === "object" && address ? address.port : null;
|
||||
await new Promise<void>((resolve, reject) => probe.close((e) => (e ? reject(e) : resolve())));
|
||||
if (!port) throw new Error("failed to reserve a legacy port");
|
||||
return port;
|
||||
for (let attempt = 0; attempt < 100; attempt += 1) {
|
||||
const probe = net.createServer();
|
||||
await new Promise<void>((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
||||
const address = probe.address();
|
||||
const port = typeof address === "object" && address ? address.port : null;
|
||||
await new Promise<void>((resolve, reject) => probe.close((e) => (e ? reject(e) : resolve())));
|
||||
if (port && port <= 55_535 && (port < 42_000 || port > 42_999)) return port;
|
||||
}
|
||||
throw new Error("failed to reserve a legacy port outside the broker range");
|
||||
};
|
||||
|
||||
const companyId = randomUUID();
|
||||
|
||||
@@ -6580,15 +6580,17 @@ describeEmbeddedPostgres("workspace runtime startup reconciliation", () => {
|
||||
process.env.PAPERCLIP_INSTANCE_ID = `runtime-https-backfill-${randomUUID()}`;
|
||||
|
||||
const reservePort = async () => {
|
||||
const probe = net.createServer();
|
||||
await new Promise<void>((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
||||
const address = probe.address();
|
||||
const port = typeof address === "object" && address ? address.port : null;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
probe.close((error) => error ? reject(error) : resolve());
|
||||
});
|
||||
if (!port) throw new Error("Failed to reserve HTTPS backfill test port");
|
||||
return port;
|
||||
for (let attempt = 0; attempt < 100; attempt += 1) {
|
||||
const probe = net.createServer();
|
||||
await new Promise<void>((resolve) => probe.listen(0, "127.0.0.1", resolve));
|
||||
const address = probe.address();
|
||||
const port = typeof address === "object" && address ? address.port : null;
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
probe.close((error) => error ? reject(error) : resolve());
|
||||
});
|
||||
if (port && port <= 55_535 && (port < 42_000 || port > 42_999)) return port;
|
||||
}
|
||||
throw new Error("Failed to reserve an HTTPS backfill test port outside the broker range");
|
||||
};
|
||||
const isLoopbackPortFree = async (port: number) => {
|
||||
const probe = net.createServer();
|
||||
|
||||
@@ -4801,6 +4801,48 @@ async function spawnLocalRuntimeService(input: StartLocalRuntimeServiceInput): P
|
||||
scopeType: input.scopeType,
|
||||
scopeId: input.scopeId,
|
||||
});
|
||||
let fixedPortRegistryMatch = false;
|
||||
if (!exposureConfig && canAllocateFixedPort && identityPort) {
|
||||
const identityTemplateData = buildTemplateData({
|
||||
workspace: input.workspace,
|
||||
agent: input.agent,
|
||||
issue: input.issue,
|
||||
adapterEnv: input.adapterEnv,
|
||||
port: identityPort,
|
||||
});
|
||||
const identityExpose = parseObject(input.service.expose);
|
||||
const identityReadiness = parseObject(input.service.readiness);
|
||||
const identityUrlTemplate =
|
||||
asString(identityExpose.urlTemplate, "")
|
||||
|| asString(identityReadiness.urlTemplate, "");
|
||||
const identityBackendUrl = identityUrlTemplate
|
||||
? renderTemplate(identityUrlTemplate, identityTemplateData)
|
||||
: null;
|
||||
const identityServiceKey = createLocalServiceKey({
|
||||
profileKind: "workspace-runtime",
|
||||
serviceName,
|
||||
cwd: identity.serviceCwd,
|
||||
command,
|
||||
envFingerprint: serviceIdentityFingerprint,
|
||||
port: identityPort,
|
||||
scope: {
|
||||
scopeType: input.scopeType,
|
||||
scopeId: input.scopeId,
|
||||
executionWorkspaceId: input.executionWorkspaceId ?? null,
|
||||
reuseKey: input.reuseKey,
|
||||
},
|
||||
});
|
||||
fixedPortRegistryMatch = Boolean(await findAdoptableLocalService({
|
||||
serviceKey: identityServiceKey,
|
||||
profileKind: "workspace-runtime",
|
||||
serviceName,
|
||||
command,
|
||||
cwd: identity.serviceCwd,
|
||||
envFingerprint: serviceIdentityFingerprint,
|
||||
port: identityPort,
|
||||
url: identityBackendUrl,
|
||||
}));
|
||||
}
|
||||
const runtimeId = input.runtimeServiceId ?? stoppedReuseCandidate?.id ?? randomUUID();
|
||||
// An exposed runtime always takes its port from the dedicated broker range, so
|
||||
// a configured or previously used port is a *preference*, not a constraint. It
|
||||
@@ -4838,6 +4880,8 @@ async function spawnLocalRuntimeService(input: StartLocalRuntimeServiceInput): P
|
||||
remediation: "Retry the start or configure a different runtime service port.",
|
||||
});
|
||||
}
|
||||
} else if (!reservedExposure && canAllocateFixedPort && fixedPortRegistryMatch) {
|
||||
port = explicitPort;
|
||||
} else if (!reservedExposure && canAllocateFixedPort) {
|
||||
port = await allocateIsolatedWorkspacePort({
|
||||
db: input.db,
|
||||
|
||||
Reference in new issue
Block a user