@ricsam/r5d-worker 0.0.59 → 0.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/main.cjs +303 -381
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/workspace-convergence.cjs +42 -106
- package/dist/cjs/workspace-manifest-admission.cjs +4 -10
- package/dist/cjs/workspace-sync.cjs +2 -8
- package/dist/mjs/main.mjs +310 -396
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/workspace-convergence.mjs +37 -99
- package/dist/mjs/workspace-manifest-admission.mjs +3 -8
- package/dist/mjs/workspace-sync.mjs +2 -8
- package/dist/types/workspace-convergence.d.ts +15 -35
- package/dist/types/workspace-incident-state.d.ts +1 -1
- package/dist/types/workspace-manifest-admission.d.ts +6 -9
- package/dist/types/workspace-sync.d.ts +1 -1
- package/package.json +1 -1
package/dist/cjs/main.cjs
CHANGED
|
@@ -86,7 +86,6 @@ const cancelledProcessRuns = /* @__PURE__ */ new Set();
|
|
|
86
86
|
const activePtys = /* @__PURE__ */ new Map();
|
|
87
87
|
let currentWorkerSocket = null;
|
|
88
88
|
const workspaceSyncSingleFlight = new import_workspace_sync.WorkspaceSyncSingleFlight();
|
|
89
|
-
const workspaceFilesystemWriters = (0, import_workspace_convergence.processWorkspaceFilesystemWriterGate)();
|
|
90
89
|
let githubCredential = null;
|
|
91
90
|
let visibleGitIdentity = null;
|
|
92
91
|
function defaultConfigPath() {
|
|
@@ -808,25 +807,13 @@ function fallbackInternalRemoteUrl(baseUrl, projectId) {
|
|
|
808
807
|
}
|
|
809
808
|
function visibleCheckoutRemoteFor(input) {
|
|
810
809
|
const canonicalCheckout = input.manifest?.canonicalCheckouts?.find((checkout) => checkout.branchName === input.branchName);
|
|
811
|
-
const isCanonicalManifestBranch = Boolean(canonicalCheckout);
|
|
812
|
-
const usesCanonicalRemote = isCanonicalManifestBranch || !input.manifest?.repoHttpUrl;
|
|
813
|
-
if (usesCanonicalRemote) {
|
|
814
|
-
return {
|
|
815
|
-
remoteUrl: fallbackInternalRemoteUrl(input.baseUrl, input.projectId),
|
|
816
|
-
authHeader: `Authorization: Bearer ${input.token}`,
|
|
817
|
-
persistAuth: false,
|
|
818
|
-
reconcileExistingOrigin: isCanonicalManifestBranch,
|
|
819
|
-
requireRemoteBranch: isCanonicalManifestBranch,
|
|
820
|
-
requiredBaseCommit: canonicalCheckout?.scaffoldCommitHash ?? null
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
810
|
return {
|
|
824
|
-
remoteUrl:
|
|
825
|
-
authHeader: input.
|
|
826
|
-
persistAuth:
|
|
827
|
-
reconcileExistingOrigin:
|
|
828
|
-
requireRemoteBranch:
|
|
829
|
-
requiredBaseCommit: null
|
|
811
|
+
remoteUrl: fallbackInternalRemoteUrl(input.baseUrl, input.projectId),
|
|
812
|
+
authHeader: `Authorization: Bearer ${input.token}`,
|
|
813
|
+
persistAuth: false,
|
|
814
|
+
reconcileExistingOrigin: true,
|
|
815
|
+
requireRemoteBranch: true,
|
|
816
|
+
requiredBaseCommit: canonicalCheckout?.scaffoldCommitHash ?? null
|
|
830
817
|
};
|
|
831
818
|
}
|
|
832
819
|
function gitExtraHeaderUrlForRemote(remoteUrl) {
|
|
@@ -1047,9 +1034,11 @@ function checkoutVisibleBranch(input) {
|
|
|
1047
1034
|
}
|
|
1048
1035
|
function migrateExistingCheckoutToRequiredRemote(input) {
|
|
1049
1036
|
if (originRemoteUrl(input.branchPath) === input.remoteUrl) return;
|
|
1050
|
-
|
|
1037
|
+
const dirtyWorkingTree = hasWorktreeChanges(input.branchPath);
|
|
1038
|
+
if (dirtyWorkingTree && input.requiredBaseCommit) {
|
|
1051
1039
|
throw new Error(`Cannot migrate dirty checkout for ${input.branchName} to its canonical remote`);
|
|
1052
1040
|
}
|
|
1041
|
+
const preserveWorkingTree = dirtyWorkingTree;
|
|
1053
1042
|
runGit(
|
|
1054
1043
|
visibleCheckoutFetchArgs("--no-tags", input.remoteUrl, `+refs/heads/${input.branchName}:refs/remotes/origin/${input.branchName}`),
|
|
1055
1044
|
{
|
|
@@ -1064,11 +1053,12 @@ function migrateExistingCheckoutToRequiredRemote(input) {
|
|
|
1064
1053
|
if (input.requiredBaseCommit && (!tryGit(["cat-file", "-e", `${input.requiredBaseCommit}^{commit}`], { cwd: input.branchPath }) || !tryGit(["merge-base", "--is-ancestor", input.requiredBaseCommit, canonicalRemoteRef], { cwd: input.branchPath }))) {
|
|
1065
1054
|
throw new Error(`Canonical branch ${input.branchName} is not derived from required scaffold ${input.requiredBaseCommit}`);
|
|
1066
1055
|
}
|
|
1056
|
+
ensureOriginRemote(input.branchPath, input.remoteUrl);
|
|
1057
|
+
if (preserveWorkingTree) return;
|
|
1067
1058
|
if (tryGit(["rev-parse", "--verify", "HEAD"], { cwd: input.branchPath })) {
|
|
1068
1059
|
const previousHead = runGit(["rev-parse", "HEAD"], { cwd: input.branchPath });
|
|
1069
1060
|
runGit(["update-ref", `refs/r5d/pre-canonical-checkout/${previousHead}`, previousHead], { cwd: input.branchPath });
|
|
1070
1061
|
}
|
|
1071
|
-
ensureOriginRemote(input.branchPath, input.remoteUrl);
|
|
1072
1062
|
runGit(["checkout", "--no-recurse-submodules", "-B", input.branchName, `origin/${input.branchName}`], {
|
|
1073
1063
|
cwd: input.branchPath
|
|
1074
1064
|
});
|
|
@@ -1161,7 +1151,7 @@ function ensureVisibleGitCheckout(input) {
|
|
|
1161
1151
|
(0, import_git_identity.configureVisibleGitIdentity)(branchPath, visibleGitIdentity, runGit);
|
|
1162
1152
|
return branchPath;
|
|
1163
1153
|
}
|
|
1164
|
-
function
|
|
1154
|
+
function ensureBranchWorktree(input) {
|
|
1165
1155
|
const defaultBranch = input.manifest?.defaultBranch || "main";
|
|
1166
1156
|
const remote = visibleCheckoutRemoteFor(input);
|
|
1167
1157
|
return {
|
|
@@ -1194,7 +1184,7 @@ function resolveWorkerSessionTarget(input) {
|
|
|
1194
1184
|
}
|
|
1195
1185
|
const manifest = input.manifestByProjectId.get(input.target.projectId);
|
|
1196
1186
|
const projectRoot = projectRootFor(input.projectsRoot, input.target.projectId, input.manifestByProjectId);
|
|
1197
|
-
const
|
|
1187
|
+
const worktree = ensureBranchWorktree({
|
|
1198
1188
|
projectId: input.target.projectId,
|
|
1199
1189
|
baseUrl: input.baseUrl,
|
|
1200
1190
|
token: input.token,
|
|
@@ -1203,7 +1193,7 @@ function resolveWorkerSessionTarget(input) {
|
|
|
1203
1193
|
branchName: input.target.branchName,
|
|
1204
1194
|
manifest
|
|
1205
1195
|
});
|
|
1206
|
-
return { target: input.target, rootPath:
|
|
1196
|
+
return { target: input.target, rootPath: worktree.branchPath, manifest };
|
|
1207
1197
|
}
|
|
1208
1198
|
function workspaceSyncCheckoutTargets(input) {
|
|
1209
1199
|
const selected = /* @__PURE__ */ new Map();
|
|
@@ -2408,15 +2398,15 @@ async function startWorker(options) {
|
|
|
2408
2398
|
const workspaceConvergence = (0, import_workspace_convergence.processWorkspaceConvergenceState)(import_node_path.default.join(syncRoot, "workspace-convergence.json"));
|
|
2409
2399
|
const workspaceManifestRevision = new import_workspace_convergence.WorkspaceManifestRevisionFence();
|
|
2410
2400
|
let workspaceReady = false;
|
|
2411
|
-
let
|
|
2401
|
+
let workspacePublicationTimer;
|
|
2412
2402
|
let workspaceSafetyScan;
|
|
2413
2403
|
let workspaceManifestHydrationTimer;
|
|
2414
2404
|
let workspaceManifestHydrationInFlight = false;
|
|
2415
2405
|
let workspaceSafetyScanInFlight = false;
|
|
2416
2406
|
let workspaceHeadConvergenceInFlight = false;
|
|
2417
2407
|
let pendingWorkspaceHead;
|
|
2418
|
-
let
|
|
2419
|
-
const
|
|
2408
|
+
let pendingPublication;
|
|
2409
|
+
const explicitWorkspacePublications = new import_workspace_convergence.ExplicitWorkspacePublicationQueue();
|
|
2420
2410
|
let terminalReplayTimer;
|
|
2421
2411
|
let workspaceSyncRequestsInFlight = 0;
|
|
2422
2412
|
let sessionArtifactSyncRequestsInFlight = 0;
|
|
@@ -2463,121 +2453,110 @@ async function startWorker(options) {
|
|
|
2463
2453
|
})
|
|
2464
2454
|
);
|
|
2465
2455
|
} catch (error) {
|
|
2466
|
-
process.stderr.write(
|
|
2467
|
-
|
|
2468
|
-
`
|
|
2469
|
-
);
|
|
2456
|
+
process.stderr.write(`[r5d-worker] failed to send workspace readiness: ${error instanceof Error ? error.message : String(error)}
|
|
2457
|
+
`);
|
|
2470
2458
|
}
|
|
2471
2459
|
};
|
|
2472
|
-
const workerHasActiveWriter = () => activeProcesses.size > 0 || activePtys.size > 0 || cliUpdateInProgress;
|
|
2473
2460
|
const targetMayMutateVisibleWorkspace = (target) => target.type === "project" || target.rootProfile === "visible_projects";
|
|
2474
|
-
const
|
|
2461
|
+
const armWorkspacePublication = (trigger, options2 = { delayMs: import_workspace_convergence.WORKSPACE_PUBLICATION_QUIET_MS }) => {
|
|
2475
2462
|
workspaceConvergence.schedule();
|
|
2476
2463
|
if (currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) return;
|
|
2477
2464
|
sendWorkspaceReady();
|
|
2478
|
-
if (options2.requestId && !
|
|
2465
|
+
if (options2.requestId && !explicitWorkspacePublications.schedule({ requestId: options2.requestId, trigger }, pendingPublication?.requestId)) {
|
|
2479
2466
|
return;
|
|
2480
2467
|
}
|
|
2481
|
-
if (!options2.requestId &&
|
|
2482
|
-
if (
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2468
|
+
if (!options2.requestId && explicitWorkspacePublications.hasScheduled()) return;
|
|
2469
|
+
if (workspacePublicationTimer) clearTimeout(workspacePublicationTimer);
|
|
2470
|
+
workspacePublicationTimer = setTimeout(
|
|
2471
|
+
() => {
|
|
2472
|
+
workspacePublicationTimer = void 0;
|
|
2473
|
+
if (options2.requestId) explicitWorkspacePublications.consumeScheduled(options2.requestId);
|
|
2474
|
+
if (currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) return;
|
|
2475
|
+
if (!workspaceReady || !workspaceRemoteUrl) {
|
|
2476
|
+
armWorkspacePublication(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2479
|
+
if (activeWorkspaceIncidentId) {
|
|
2480
|
+
workspaceConvergence.block();
|
|
2481
|
+
sendWorkspaceReady();
|
|
2482
|
+
if ((0, import_workspace_convergence.workspacePublicationIncidentAction)(options2.requestId) === "defer_automatic") return;
|
|
2483
|
+
if (pendingPublication) {
|
|
2484
|
+
explicitWorkspacePublications.enqueue({ requestId: options2.requestId, trigger }, pendingPublication.requestId);
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
const snapshot2 = workspaceConvergence.snapshot();
|
|
2488
|
+
pendingPublication = {
|
|
2489
|
+
requestId: options2.requestId,
|
|
2490
|
+
trigger,
|
|
2491
|
+
dirtyGeneration: snapshot2.dirtyGeneration,
|
|
2492
|
+
explicit: true,
|
|
2493
|
+
workInFlight: false,
|
|
2494
|
+
requestedAt: Date.now()
|
|
2495
|
+
};
|
|
2496
|
+
try {
|
|
2497
|
+
ws.send(
|
|
2498
|
+
JSON.stringify({
|
|
2499
|
+
type: "workspace_publication_request",
|
|
2500
|
+
requestId: options2.requestId,
|
|
2501
|
+
trigger,
|
|
2502
|
+
dirtyGeneration: snapshot2.dirtyGeneration,
|
|
2503
|
+
localHead: snapshot2.localHead,
|
|
2504
|
+
desiredCanonicalHead: snapshot2.desiredCanonicalHead
|
|
2505
|
+
})
|
|
2506
|
+
);
|
|
2507
|
+
} catch (error) {
|
|
2508
|
+
pendingPublication = void 0;
|
|
2509
|
+
workspaceConvergence.defer();
|
|
2510
|
+
process.stderr.write(
|
|
2511
|
+
`[r5d-worker] failed to request blocked workspace publication authority: ${error instanceof Error ? error.message : String(error)}
|
|
2512
|
+
`
|
|
2513
|
+
);
|
|
2514
|
+
armWorkspacePublication(trigger, { delayMs: 1e3, requestId: options2.requestId });
|
|
2515
|
+
}
|
|
2497
2516
|
return;
|
|
2498
2517
|
}
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2518
|
+
if (pendingPublication) {
|
|
2519
|
+
armWorkspacePublication(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
const snapshot = workspaceConvergence.snapshot();
|
|
2523
|
+
const requestId = options2.requestId ?? crypto.randomUUID();
|
|
2524
|
+
pendingPublication = {
|
|
2525
|
+
requestId,
|
|
2502
2526
|
trigger,
|
|
2503
|
-
dirtyGeneration:
|
|
2504
|
-
explicit:
|
|
2505
|
-
admissionHeld: false,
|
|
2527
|
+
dirtyGeneration: snapshot.dirtyGeneration,
|
|
2528
|
+
explicit: options2.requestId !== void 0,
|
|
2506
2529
|
workInFlight: false,
|
|
2507
|
-
requestedAt: Date.now()
|
|
2508
|
-
releaseCheckpointAdmission: () => {
|
|
2509
|
-
}
|
|
2530
|
+
requestedAt: Date.now()
|
|
2510
2531
|
};
|
|
2511
2532
|
try {
|
|
2512
2533
|
ws.send(
|
|
2513
2534
|
JSON.stringify({
|
|
2514
|
-
type: "
|
|
2515
|
-
requestId
|
|
2535
|
+
type: "workspace_publication_request",
|
|
2536
|
+
requestId,
|
|
2516
2537
|
trigger,
|
|
2517
|
-
dirtyGeneration:
|
|
2518
|
-
localHead:
|
|
2519
|
-
desiredCanonicalHead:
|
|
2538
|
+
dirtyGeneration: snapshot.dirtyGeneration,
|
|
2539
|
+
localHead: snapshot.localHead,
|
|
2540
|
+
desiredCanonicalHead: snapshot.desiredCanonicalHead
|
|
2520
2541
|
})
|
|
2521
2542
|
);
|
|
2522
2543
|
} catch (error) {
|
|
2523
|
-
|
|
2544
|
+
pendingPublication = void 0;
|
|
2524
2545
|
workspaceConvergence.defer();
|
|
2525
2546
|
process.stderr.write(
|
|
2526
|
-
`[r5d-worker] failed to request
|
|
2547
|
+
`[r5d-worker] failed to request workspace publication: ${error instanceof Error ? error.message : String(error)}
|
|
2527
2548
|
`
|
|
2528
2549
|
);
|
|
2529
|
-
|
|
2550
|
+
armWorkspacePublication(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
|
|
2530
2551
|
}
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
return;
|
|
2536
|
-
}
|
|
2537
|
-
const releaseCheckpointAdmission = workspaceFilesystemWriters.tryAcquireCheckpoint();
|
|
2538
|
-
if (!releaseCheckpointAdmission) {
|
|
2539
|
-
armWorkspaceCheckpoint(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
|
|
2540
|
-
return;
|
|
2541
|
-
}
|
|
2542
|
-
const snapshot = workspaceConvergence.snapshot();
|
|
2543
|
-
const requestId = options2.requestId ?? crypto.randomUUID();
|
|
2544
|
-
pendingCheckpoint = {
|
|
2545
|
-
requestId,
|
|
2546
|
-
trigger,
|
|
2547
|
-
dirtyGeneration: snapshot.dirtyGeneration,
|
|
2548
|
-
explicit: options2.requestId !== void 0,
|
|
2549
|
-
admissionHeld: true,
|
|
2550
|
-
workInFlight: false,
|
|
2551
|
-
requestedAt: Date.now(),
|
|
2552
|
-
releaseCheckpointAdmission
|
|
2553
|
-
};
|
|
2554
|
-
try {
|
|
2555
|
-
ws.send(
|
|
2556
|
-
JSON.stringify({
|
|
2557
|
-
type: "workspace_checkpoint_request",
|
|
2558
|
-
requestId,
|
|
2559
|
-
trigger,
|
|
2560
|
-
dirtyGeneration: snapshot.dirtyGeneration,
|
|
2561
|
-
localHead: snapshot.localHead,
|
|
2562
|
-
desiredCanonicalHead: snapshot.desiredCanonicalHead
|
|
2563
|
-
})
|
|
2564
|
-
);
|
|
2565
|
-
} catch (error) {
|
|
2566
|
-
releaseCheckpointAdmission();
|
|
2567
|
-
pendingCheckpoint = void 0;
|
|
2568
|
-
workspaceConvergence.defer();
|
|
2569
|
-
process.stderr.write(
|
|
2570
|
-
`[r5d-worker] failed to request workspace checkpoint: ${error instanceof Error ? error.message : String(error)}
|
|
2571
|
-
`
|
|
2572
|
-
);
|
|
2573
|
-
armWorkspaceCheckpoint(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
|
|
2574
|
-
}
|
|
2575
|
-
}, Math.max(0, options2.delayMs));
|
|
2576
|
-
workspaceCheckpointTimer.unref();
|
|
2552
|
+
},
|
|
2553
|
+
Math.max(0, options2.delayMs)
|
|
2554
|
+
);
|
|
2555
|
+
workspacePublicationTimer.unref();
|
|
2577
2556
|
};
|
|
2578
2557
|
const markWorkspaceDirty = (trigger, force = false) => {
|
|
2579
2558
|
workspaceConvergence.markDirty();
|
|
2580
|
-
|
|
2559
|
+
armWorkspacePublication(trigger, { delayMs: force ? 0 : import_workspace_convergence.WORKSPACE_PUBLICATION_QUIET_MS });
|
|
2581
2560
|
};
|
|
2582
2561
|
const convergeAvailableWorkspaceHead = async () => {
|
|
2583
2562
|
if (pendingWorkspaceHead === void 0 || !workspaceReady || !workspaceRemoteUrl || activeWorkspaceIncidentId || workspaceHeadConvergenceInFlight) {
|
|
@@ -2587,12 +2566,9 @@ async function startWorker(options) {
|
|
|
2587
2566
|
pendingWorkspaceHead = void 0;
|
|
2588
2567
|
workspaceConvergence.observeCanonicalHead(advertisedHead);
|
|
2589
2568
|
workspaceHeadConvergenceInFlight = true;
|
|
2590
|
-
let releaseVisibleHydration = null;
|
|
2591
2569
|
try {
|
|
2592
2570
|
const snapshot = workspaceConvergence.snapshot();
|
|
2593
|
-
const
|
|
2594
|
-
releaseVisibleHydration = mayHydrateVisible ? workspaceFilesystemWriters.tryAcquireCheckpoint() : null;
|
|
2595
|
-
const hydrateVisible = releaseVisibleHydration !== null;
|
|
2571
|
+
const hydrateVisible = !pendingPublication && snapshot.dirtyGeneration === snapshot.publishedGeneration;
|
|
2596
2572
|
const converged = await workspaceSyncSingleFlight.runExclusive(
|
|
2597
2573
|
() => (0, import_workspace_sync.convergeWorkspaceHead)(workspaceSyncInput({ type: "inbound_head", detail: advertisedHead ?? "unborn" }), {
|
|
2598
2574
|
hydrateVisible
|
|
@@ -2601,7 +2577,7 @@ async function startWorker(options) {
|
|
|
2601
2577
|
workspaceConvergence.observeCanonicalHead(converged.canonicalHead);
|
|
2602
2578
|
if (converged.hydrated) workspaceConvergence.setLocalHead(converged.localHead);
|
|
2603
2579
|
if (hydrateVisible && converged.localChanges) {
|
|
2604
|
-
markWorkspaceDirty({ type: "periodic", detail: "inbound overlap retained for next
|
|
2580
|
+
markWorkspaceDirty({ type: "periodic", detail: "inbound overlap retained for next publication" });
|
|
2605
2581
|
}
|
|
2606
2582
|
sendWorkspaceReady();
|
|
2607
2583
|
} catch (error) {
|
|
@@ -2611,7 +2587,6 @@ async function startWorker(options) {
|
|
|
2611
2587
|
`
|
|
2612
2588
|
);
|
|
2613
2589
|
} finally {
|
|
2614
|
-
releaseVisibleHydration?.();
|
|
2615
2590
|
workspaceHeadConvergenceInFlight = false;
|
|
2616
2591
|
heartbeatBusyGrace = (0, import_heartbeat.grantWorkerHeartbeatBusyGrace)(lastServerHeartbeatAt, heartbeatBusyGrace);
|
|
2617
2592
|
if (pendingWorkspaceHead !== void 0) {
|
|
@@ -2632,7 +2607,7 @@ async function startWorker(options) {
|
|
|
2632
2607
|
workspaceShadowRoot,
|
|
2633
2608
|
manifestByProjectId
|
|
2634
2609
|
});
|
|
2635
|
-
const
|
|
2610
|
+
const ensureVisibleWorktrees = (targets, options2 = {}) => {
|
|
2636
2611
|
const created = [];
|
|
2637
2612
|
for (const target of targets) {
|
|
2638
2613
|
const manifest = manifestByProjectId.get(target.projectId);
|
|
@@ -2661,7 +2636,7 @@ async function startWorker(options) {
|
|
|
2661
2636
|
reconcileExistingOrigin: remote.reconcileExistingOrigin,
|
|
2662
2637
|
requireRemoteBranch: remote.requireRemoteBranch,
|
|
2663
2638
|
requiredBaseCommit: remote.requiredBaseCommit,
|
|
2664
|
-
allowRequiredRemoteMigration: !(options2.strictCanonicalRevalidation && remote.
|
|
2639
|
+
allowRequiredRemoteMigration: !(options2.strictCanonicalRevalidation && remote.requiredBaseCommit),
|
|
2665
2640
|
clearPersistentAuth: !remote.persistAuth
|
|
2666
2641
|
});
|
|
2667
2642
|
if (!existed) created.push(target);
|
|
@@ -2672,46 +2647,43 @@ async function startWorker(options) {
|
|
|
2672
2647
|
if (workspaceManifestHydrationTimer || workspaceManifestHydrationInFlight || pendingManifestCheckouts.size === 0 || currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) {
|
|
2673
2648
|
return;
|
|
2674
2649
|
}
|
|
2675
|
-
workspaceManifestHydrationTimer = setTimeout(
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
if (pendingManifestCheckouts.size
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
}
|
|
2683
|
-
const releaseHydration = workspaceFilesystemWriters.tryAcquireCheckpoint();
|
|
2684
|
-
if (!releaseHydration) {
|
|
2685
|
-
schedulePendingManifestCheckoutHydration(1e3);
|
|
2686
|
-
return;
|
|
2687
|
-
}
|
|
2688
|
-
workspaceManifestHydrationInFlight = true;
|
|
2689
|
-
void workspaceSyncSingleFlight.runExclusive(async () => {
|
|
2690
|
-
if (!workspaceReady || activeWorkspaceIncidentId || currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) {
|
|
2650
|
+
workspaceManifestHydrationTimer = setTimeout(
|
|
2651
|
+
() => {
|
|
2652
|
+
workspaceManifestHydrationTimer = void 0;
|
|
2653
|
+
if (!workspaceReady || !workspaceRemoteUrl || activeWorkspaceIncidentId || pendingPublication || pendingManifestCheckouts.size === 0 || currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) {
|
|
2654
|
+
if (pendingManifestCheckouts.size > 0 && currentWorkerSocket === ws && ws.readyState === WebSocket.OPEN) {
|
|
2655
|
+
schedulePendingManifestCheckoutHydration(1e3);
|
|
2656
|
+
}
|
|
2691
2657
|
return;
|
|
2692
2658
|
}
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
if (!manifest || !manifest.branches.includes(target.branchName)) continue;
|
|
2698
|
-
const branchPath = import_node_path.default.join(projectRootFor(projectsRoot, target.projectId, manifestByProjectId), target.branchName);
|
|
2699
|
-
if (hasNormalVisibleGitDir(branchPath)) {
|
|
2700
|
-
pendingManifestCheckouts.delete(manifestCheckoutKey(target.projectId, target.branchName));
|
|
2659
|
+
workspaceManifestHydrationInFlight = true;
|
|
2660
|
+
void workspaceSyncSingleFlight.runExclusive(async () => {
|
|
2661
|
+
if (!workspaceReady || activeWorkspaceIncidentId || currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) {
|
|
2662
|
+
return;
|
|
2701
2663
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2664
|
+
const targets = [...pendingManifestCheckouts.values()];
|
|
2665
|
+
ensureVisibleWorktrees(targets, { strictCanonicalRevalidation: true });
|
|
2666
|
+
for (const target of targets) {
|
|
2667
|
+
const manifest = manifestByProjectId.get(target.projectId);
|
|
2668
|
+
if (!manifest || !manifest.branches.includes(target.branchName)) continue;
|
|
2669
|
+
const branchPath = import_node_path.default.join(projectRootFor(projectsRoot, target.projectId, manifestByProjectId), target.branchName);
|
|
2670
|
+
if (hasNormalVisibleGitDir(branchPath)) {
|
|
2671
|
+
pendingManifestCheckouts.delete(manifestCheckoutKey(target.projectId, target.branchName));
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}).then(() => sendWorkspaceReady()).catch((error) => {
|
|
2675
|
+
process.stderr.write(
|
|
2676
|
+
`[r5d-worker] pending manifest checkout hydration failed: ${error instanceof Error ? error.message : String(error)}
|
|
2706
2677
|
`
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
}
|
|
2714
|
-
|
|
2678
|
+
);
|
|
2679
|
+
}).finally(() => {
|
|
2680
|
+
workspaceManifestHydrationInFlight = false;
|
|
2681
|
+
heartbeatBusyGrace = (0, import_heartbeat.grantWorkerHeartbeatBusyGrace)(lastServerHeartbeatAt, heartbeatBusyGrace);
|
|
2682
|
+
if (pendingManifestCheckouts.size > 0) schedulePendingManifestCheckoutHydration(1e3);
|
|
2683
|
+
});
|
|
2684
|
+
},
|
|
2685
|
+
Math.max(0, delayMs)
|
|
2686
|
+
);
|
|
2715
2687
|
workspaceManifestHydrationTimer.unref();
|
|
2716
2688
|
};
|
|
2717
2689
|
const runRequestedWorkspaceSync = async (authority, trigger, overrides = {}) => {
|
|
@@ -2745,7 +2717,7 @@ async function startWorker(options) {
|
|
|
2745
2717
|
});
|
|
2746
2718
|
}
|
|
2747
2719
|
pendingTargets = shouldEnsureCheckouts ? scopedPendingTargets : [];
|
|
2748
|
-
const createdCheckouts =
|
|
2720
|
+
const createdCheckouts = ensureVisibleWorktrees(checkoutTargets, {
|
|
2749
2721
|
strictCanonicalRevalidation: true
|
|
2750
2722
|
});
|
|
2751
2723
|
const newVisibleCheckoutByKey = /* @__PURE__ */ new Map();
|
|
@@ -2827,11 +2799,11 @@ async function startWorker(options) {
|
|
|
2827
2799
|
const handleGracefulShutdown = () => {
|
|
2828
2800
|
if (shutdownAfterClose) return;
|
|
2829
2801
|
shutdownAfterClose = true;
|
|
2830
|
-
void (0, import_workspace_convergence.
|
|
2802
|
+
void (0, import_workspace_convergence.waitForWorkspacePublicationOnShutdown)({
|
|
2831
2803
|
snapshot: () => workspaceConvergence.snapshot(),
|
|
2832
|
-
|
|
2804
|
+
forcePublication: () => armWorkspacePublication({ type: "manual", detail: "graceful worker shutdown" }, { delayMs: 0 })
|
|
2833
2805
|
}).then((outcome) => {
|
|
2834
|
-
process.stdout.write(`[r5d-worker] graceful workspace
|
|
2806
|
+
process.stdout.write(`[r5d-worker] graceful workspace publication ${outcome}
|
|
2835
2807
|
`);
|
|
2836
2808
|
if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
|
|
2837
2809
|
ws.close(1e3, "Worker shutting down");
|
|
@@ -2902,105 +2874,84 @@ async function startWorker(options) {
|
|
|
2902
2874
|
if (message.type === "workspace_manifest") {
|
|
2903
2875
|
const revisionToken = workspaceManifestRevision.begin(message.revision);
|
|
2904
2876
|
workspaceReady = false;
|
|
2905
|
-
const
|
|
2877
|
+
const manifestFilesystem = (0, import_workspace_manifest_admission.inspectWorkspaceManifestFilesystem)({
|
|
2906
2878
|
projectsRoot,
|
|
2907
2879
|
workspaceShadowRoot,
|
|
2908
2880
|
projects: message.projects
|
|
2909
2881
|
});
|
|
2910
|
-
const
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
);
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
hydrateVisible: firstBootstrap && !activeWorkspaceIncidentId
|
|
2952
|
-
}
|
|
2953
|
-
);
|
|
2954
|
-
if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
|
|
2955
|
-
workspaceConvergence.setLocalHead(bootstrapped.localHead);
|
|
2956
|
-
workspaceConvergence.observeCanonicalHead(bootstrapped.canonicalHead);
|
|
2957
|
-
for (const checkout of currentCheckouts) {
|
|
2958
|
-
const manifest = manifestByProjectId.get(checkout.projectId);
|
|
2959
|
-
if (!manifest) continue;
|
|
2960
|
-
const branchPath = import_node_path.default.join(projectRootFor(projectsRoot, checkout.projectId, manifestByProjectId), checkout.branchName);
|
|
2961
|
-
if (hasNormalVisibleGitDir(branchPath)) {
|
|
2962
|
-
pendingManifestCheckouts.delete(manifestCheckoutKey(checkout.projectId, checkout.branchName));
|
|
2963
|
-
}
|
|
2882
|
+
const completed = await workspaceSyncSingleFlight.runExclusive(async () => {
|
|
2883
|
+
if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
|
|
2884
|
+
const firstBootstrap = manifestFilesystem.firstBootstrap;
|
|
2885
|
+
configureGitHubAuth(message.githubCredential);
|
|
2886
|
+
visibleGitIdentity = message.gitIdentity;
|
|
2887
|
+
workspaceRemoteUrl = message.workspaceRemoteUrl;
|
|
2888
|
+
const migratedProjectIds = (0, import_managed_paths.migrateLegacyProjectRoots)(projectsRoot, message.projects);
|
|
2889
|
+
manifestByProjectId.clear();
|
|
2890
|
+
for (const project of message.projects) manifestByProjectId.set(project.projectId, project);
|
|
2891
|
+
const currentCheckouts = allManifestCheckouts();
|
|
2892
|
+
const currentCheckoutKeys = new Set(
|
|
2893
|
+
currentCheckouts.map(({ projectId, branchName }) => manifestCheckoutKey(projectId, branchName))
|
|
2894
|
+
);
|
|
2895
|
+
for (const key of pendingManifestCheckouts.keys()) {
|
|
2896
|
+
if (!currentCheckoutKeys.has(key)) pendingManifestCheckouts.delete(key);
|
|
2897
|
+
}
|
|
2898
|
+
for (const checkout of currentCheckouts) {
|
|
2899
|
+
const key = manifestCheckoutKey(checkout.projectId, checkout.branchName);
|
|
2900
|
+
const branchPath = import_node_path.default.join(projectRootFor(projectsRoot, checkout.projectId, manifestByProjectId), checkout.branchName);
|
|
2901
|
+
if (!hasNormalVisibleGitDir(branchPath)) pendingManifestCheckouts.set(key, checkout);
|
|
2902
|
+
}
|
|
2903
|
+
if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
|
|
2904
|
+
const created = firstBootstrap || migratedProjectIds.length > 0 ? ensureVisibleWorktrees(currentCheckouts, { strictCanonicalRevalidation: true }) : [];
|
|
2905
|
+
if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
|
|
2906
|
+
const bootstrapped = await (0, import_workspace_sync.convergeWorkspaceHead)(workspaceSyncInput({ type: "connect" }, { newVisibleCheckouts: created }), {
|
|
2907
|
+
// An existing checkout becomes routable after a fetch. Its
|
|
2908
|
+
// visible tree converges asynchronously; first bootstrap alone
|
|
2909
|
+
// must materialize the canonical snapshot before readiness.
|
|
2910
|
+
// Re-check the incident immediately before convergence so a
|
|
2911
|
+
// concurrently delivered fence forces fetch-only behavior.
|
|
2912
|
+
hydrateVisible: firstBootstrap && !activeWorkspaceIncidentId
|
|
2913
|
+
});
|
|
2914
|
+
if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
|
|
2915
|
+
workspaceConvergence.setLocalHead(bootstrapped.localHead);
|
|
2916
|
+
workspaceConvergence.observeCanonicalHead(bootstrapped.canonicalHead);
|
|
2917
|
+
for (const checkout of currentCheckouts) {
|
|
2918
|
+
const manifest = manifestByProjectId.get(checkout.projectId);
|
|
2919
|
+
if (!manifest) continue;
|
|
2920
|
+
const branchPath = import_node_path.default.join(projectRootFor(projectsRoot, checkout.projectId, manifestByProjectId), checkout.branchName);
|
|
2921
|
+
if (hasNormalVisibleGitDir(branchPath)) {
|
|
2922
|
+
pendingManifestCheckouts.delete(manifestCheckoutKey(checkout.projectId, checkout.branchName));
|
|
2964
2923
|
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2924
|
+
}
|
|
2925
|
+
process.stdout.write(
|
|
2926
|
+
`[r5d-worker] workspace manifest: ${message.projects.length} projects${migratedProjectIds.length > 0 ? `; migrated ${migratedProjectIds.length} project checkout root(s)` : ""}
|
|
2967
2927
|
`
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
} finally {
|
|
2972
|
-
releaseManifestHydration?.();
|
|
2973
|
-
}
|
|
2928
|
+
);
|
|
2929
|
+
return true;
|
|
2930
|
+
});
|
|
2974
2931
|
if (!completed || !workspaceManifestRevision.complete(revisionToken)) return;
|
|
2975
2932
|
workspaceReady = true;
|
|
2976
2933
|
sendWorkspaceReady();
|
|
2977
2934
|
schedulePendingManifestCheckoutHydration();
|
|
2978
2935
|
if (!workspaceSafetyScan) {
|
|
2979
2936
|
workspaceSafetyScan = setInterval(() => {
|
|
2980
|
-
if (!workspaceReady || !workspaceRemoteUrl || activeWorkspaceIncidentId ||
|
|
2937
|
+
if (!workspaceReady || !workspaceRemoteUrl || activeWorkspaceIncidentId || pendingPublication || workspaceSafetyScanInFlight) {
|
|
2981
2938
|
return;
|
|
2982
2939
|
}
|
|
2983
2940
|
workspaceSafetyScanInFlight = true;
|
|
2984
2941
|
void (async () => {
|
|
2985
2942
|
const before = workspaceConvergence.snapshot();
|
|
2986
|
-
const
|
|
2987
|
-
const
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
if (converged.hydrated) workspaceConvergence.setLocalHead(converged.localHead);
|
|
2997
|
-
if (converged.localChanges && hydrateVisible) {
|
|
2998
|
-
markWorkspaceDirty({ type: "periodic", detail: "idle safety scan" });
|
|
2999
|
-
}
|
|
3000
|
-
sendWorkspaceReady();
|
|
3001
|
-
} finally {
|
|
3002
|
-
releaseVisibleHydration?.();
|
|
2943
|
+
const hydrateVisible = before.dirtyGeneration === before.publishedGeneration;
|
|
2944
|
+
const converged = await workspaceSyncSingleFlight.runExclusive(
|
|
2945
|
+
() => (0, import_workspace_sync.convergeWorkspaceHead)(workspaceSyncInput({ type: "periodic", detail: "idle convergence scan" }), {
|
|
2946
|
+
hydrateVisible
|
|
2947
|
+
})
|
|
2948
|
+
);
|
|
2949
|
+
workspaceConvergence.observeCanonicalHead(converged.canonicalHead);
|
|
2950
|
+
if (converged.hydrated) workspaceConvergence.setLocalHead(converged.localHead);
|
|
2951
|
+
if (converged.localChanges && hydrateVisible) {
|
|
2952
|
+
markWorkspaceDirty({ type: "periodic", detail: "idle safety scan" });
|
|
3003
2953
|
}
|
|
2954
|
+
sendWorkspaceReady();
|
|
3004
2955
|
})().catch((error) => {
|
|
3005
2956
|
process.stderr.write(
|
|
3006
2957
|
`[r5d-worker] idle workspace safety scan failed: ${error instanceof Error ? error.message : String(error)}
|
|
@@ -3016,7 +2967,7 @@ async function startWorker(options) {
|
|
|
3016
2967
|
pendingWorkspaceHead = workspaceConvergence.snapshot().desiredCanonicalHead;
|
|
3017
2968
|
void convergeAvailableWorkspaceHead();
|
|
3018
2969
|
if (workspaceConvergence.snapshot().dirtyGeneration > workspaceConvergence.snapshot().publishedGeneration) {
|
|
3019
|
-
|
|
2970
|
+
armWorkspacePublication({ type: "periodic", detail: "resume dirty generation after reconnect" }, { delayMs: 0 });
|
|
3020
2971
|
}
|
|
3021
2972
|
return;
|
|
3022
2973
|
}
|
|
@@ -3047,59 +2998,52 @@ async function startWorker(options) {
|
|
|
3047
2998
|
void convergeAvailableWorkspaceHead();
|
|
3048
2999
|
return;
|
|
3049
3000
|
}
|
|
3050
|
-
if (message.type === "
|
|
3051
|
-
|
|
3001
|
+
if (message.type === "workspace_publication_now") {
|
|
3002
|
+
armWorkspacePublication(message.trigger, { delayMs: 0, requestId: message.requestId });
|
|
3052
3003
|
return;
|
|
3053
3004
|
}
|
|
3054
|
-
if (message.type === "
|
|
3055
|
-
const
|
|
3056
|
-
if (!
|
|
3057
|
-
process.stderr.write(`[r5d-worker] ignoring
|
|
3005
|
+
if (message.type === "workspace_publication_authority") {
|
|
3006
|
+
const publication = pendingPublication;
|
|
3007
|
+
if (!publication || publication.requestId !== message.requestId) {
|
|
3008
|
+
process.stderr.write(`[r5d-worker] ignoring publication authority for unknown request ${message.requestId}
|
|
3058
3009
|
`);
|
|
3059
3010
|
return;
|
|
3060
3011
|
}
|
|
3061
3012
|
if (message.status !== "granted") {
|
|
3062
|
-
|
|
3063
|
-
pendingCheckpoint = void 0;
|
|
3013
|
+
pendingPublication = void 0;
|
|
3064
3014
|
workspaceConvergence.observeCanonicalHead(message.canonicalHead);
|
|
3065
3015
|
const applyBlockedResponse = message.status === "blocked" && workspaceIncidentOrdering.permitsBlockedResponse(message.incidentId);
|
|
3066
3016
|
if (applyBlockedResponse) {
|
|
3067
3017
|
workspaceConvergence.block();
|
|
3068
3018
|
if (message.incidentId) activeWorkspaceIncidentId = message.incidentId;
|
|
3069
3019
|
} else {
|
|
3070
|
-
workspaceConvergence.
|
|
3020
|
+
workspaceConvergence.resetTransientPublicationState();
|
|
3071
3021
|
workspaceConvergence.observeIncidentState(Boolean(activeWorkspaceIncidentId));
|
|
3072
3022
|
if (message.status === "busy") {
|
|
3073
|
-
|
|
3023
|
+
armWorkspacePublication(publication.trigger, {
|
|
3074
3024
|
delayMs: message.retryAfterMs ?? 1e3,
|
|
3075
|
-
requestId:
|
|
3025
|
+
requestId: publication.requestId
|
|
3076
3026
|
});
|
|
3077
3027
|
} else if (!activeWorkspaceIncidentId) {
|
|
3078
|
-
const explicit =
|
|
3028
|
+
const explicit = explicitWorkspacePublications.next();
|
|
3079
3029
|
if (explicit) {
|
|
3080
|
-
|
|
3030
|
+
armWorkspacePublication(explicit.trigger, { delayMs: 0, requestId: explicit.requestId });
|
|
3081
3031
|
} else if (workspaceConvergence.snapshot().dirtyGeneration > workspaceConvergence.snapshot().publishedGeneration) {
|
|
3082
|
-
|
|
3032
|
+
armWorkspacePublication(publication.trigger, { delayMs: 0 });
|
|
3083
3033
|
}
|
|
3084
3034
|
}
|
|
3085
3035
|
}
|
|
3086
3036
|
sendWorkspaceReady();
|
|
3087
3037
|
return;
|
|
3088
3038
|
}
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
if (
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
checkpoint.workInFlight = false;
|
|
3098
|
-
workspaceConvergence.resetTransientCheckpointState();
|
|
3099
|
-
return;
|
|
3100
|
-
}
|
|
3101
|
-
checkpoint.admissionHeld = true;
|
|
3102
|
-
checkpoint.releaseCheckpointAdmission = releaseCheckpointAdmission;
|
|
3039
|
+
publication.attemptId = message.attemptId;
|
|
3040
|
+
publication.authorityToken = message.authorityToken;
|
|
3041
|
+
publication.workInFlight = true;
|
|
3042
|
+
pendingPublication = publication;
|
|
3043
|
+
if (currentWorkerSocket !== ws) {
|
|
3044
|
+
publication.workInFlight = false;
|
|
3045
|
+
workspaceConvergence.resetTransientPublicationState();
|
|
3046
|
+
return;
|
|
3103
3047
|
}
|
|
3104
3048
|
workspaceConvergence.beginPreparing();
|
|
3105
3049
|
sendWorkspaceReady();
|
|
@@ -3111,11 +3055,11 @@ async function startWorker(options) {
|
|
|
3111
3055
|
result = await workspaceSyncSingleFlight.runExclusive(async () => {
|
|
3112
3056
|
prepareStartedAt = Date.now();
|
|
3113
3057
|
const pendingTargets = [...pendingManifestCheckouts.values()];
|
|
3114
|
-
const createdCheckouts =
|
|
3058
|
+
const createdCheckouts = ensureVisibleWorktrees(pendingTargets, { strictCanonicalRevalidation: true });
|
|
3115
3059
|
synchronizeStartedAt = Date.now();
|
|
3116
3060
|
synchronizeStarted = true;
|
|
3117
3061
|
const prepared = await (0, import_workspace_sync.synchronizeWorkspace)(
|
|
3118
|
-
workspaceSyncInput(
|
|
3062
|
+
workspaceSyncInput(publication.trigger, {
|
|
3119
3063
|
attemptId: message.attemptId,
|
|
3120
3064
|
quarantineRef: message.quarantineRef,
|
|
3121
3065
|
expectedCanonicalHead: message.expectedHead,
|
|
@@ -3133,7 +3077,7 @@ async function startWorker(options) {
|
|
|
3133
3077
|
type: "workspace_sync",
|
|
3134
3078
|
attemptId: message.attemptId,
|
|
3135
3079
|
workerLabel: label,
|
|
3136
|
-
trigger:
|
|
3080
|
+
trigger: publication.trigger,
|
|
3137
3081
|
outcome: "failed",
|
|
3138
3082
|
startingHead: message.expectedHead,
|
|
3139
3083
|
expectedHead: message.expectedHead,
|
|
@@ -3150,9 +3094,9 @@ async function startWorker(options) {
|
|
|
3150
3094
|
const finishedAt = Date.now();
|
|
3151
3095
|
result = {
|
|
3152
3096
|
...result,
|
|
3153
|
-
dirtyGeneration:
|
|
3154
|
-
telemetry: (0, import_workspace_convergence.
|
|
3155
|
-
requestedAt:
|
|
3097
|
+
dirtyGeneration: publication.dirtyGeneration,
|
|
3098
|
+
telemetry: (0, import_workspace_convergence.workspacePublicationTelemetry)({
|
|
3099
|
+
requestedAt: publication.requestedAt,
|
|
3156
3100
|
prepareStartedAt,
|
|
3157
3101
|
synchronizeStartedAt,
|
|
3158
3102
|
finishedAt
|
|
@@ -3163,36 +3107,35 @@ async function startWorker(options) {
|
|
|
3163
3107
|
try {
|
|
3164
3108
|
ws.send(
|
|
3165
3109
|
JSON.stringify({
|
|
3166
|
-
type: "
|
|
3167
|
-
requestId:
|
|
3110
|
+
type: "workspace_publication_result",
|
|
3111
|
+
requestId: publication.requestId,
|
|
3168
3112
|
attemptId: message.attemptId,
|
|
3169
3113
|
authorityToken: message.authorityToken,
|
|
3170
|
-
dirtyGeneration:
|
|
3114
|
+
dirtyGeneration: publication.dirtyGeneration,
|
|
3171
3115
|
result
|
|
3172
3116
|
})
|
|
3173
3117
|
);
|
|
3174
3118
|
} catch (error) {
|
|
3175
|
-
workspaceConvergence.
|
|
3119
|
+
workspaceConvergence.resetTransientPublicationState();
|
|
3176
3120
|
throw error;
|
|
3177
3121
|
} finally {
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
if (currentWorkerSocket !== ws) workspaceConvergence.resetTransientCheckpointState();
|
|
3122
|
+
publication.workInFlight = false;
|
|
3123
|
+
if (currentWorkerSocket !== ws) workspaceConvergence.resetTransientPublicationState();
|
|
3181
3124
|
}
|
|
3182
3125
|
return;
|
|
3183
3126
|
}
|
|
3184
|
-
if (message.type === "
|
|
3185
|
-
const
|
|
3186
|
-
if (!
|
|
3187
|
-
process.stderr.write(`[r5d-worker] ignoring completion for unknown
|
|
3127
|
+
if (message.type === "workspace_publication_completed") {
|
|
3128
|
+
const publication = pendingPublication;
|
|
3129
|
+
if (!publication || publication.requestId !== message.requestId || publication.attemptId !== message.attemptId) {
|
|
3130
|
+
process.stderr.write(`[r5d-worker] ignoring completion for unknown publication ${message.requestId}
|
|
3188
3131
|
`);
|
|
3189
3132
|
return;
|
|
3190
3133
|
}
|
|
3191
|
-
|
|
3134
|
+
pendingPublication = void 0;
|
|
3192
3135
|
workspaceConvergence.observeCanonicalHead(message.canonicalHead);
|
|
3193
3136
|
if (message.status === "published" || message.status === "no_change") {
|
|
3194
3137
|
workspaceConvergence.complete({
|
|
3195
|
-
generation: Math.min(message.publishedGeneration ??
|
|
3138
|
+
generation: Math.min(message.publishedGeneration ?? publication.dirtyGeneration, publication.dirtyGeneration),
|
|
3196
3139
|
canonicalHead: message.canonicalHead,
|
|
3197
3140
|
published: true
|
|
3198
3141
|
});
|
|
@@ -3200,18 +3143,18 @@ async function startWorker(options) {
|
|
|
3200
3143
|
workspaceConvergence.block();
|
|
3201
3144
|
if (message.incidentId) activeWorkspaceIncidentId = message.incidentId;
|
|
3202
3145
|
} else {
|
|
3203
|
-
workspaceConvergence.
|
|
3146
|
+
workspaceConvergence.resetTransientPublicationState();
|
|
3204
3147
|
workspaceConvergence.observeIncidentState(Boolean(activeWorkspaceIncidentId));
|
|
3205
3148
|
}
|
|
3206
3149
|
sendWorkspaceReady();
|
|
3207
|
-
const explicit = message.status === "retry" &&
|
|
3150
|
+
const explicit = message.status === "retry" && publication.explicit ? { requestId: publication.requestId, trigger: publication.trigger } : explicitWorkspacePublications.next();
|
|
3208
3151
|
if (explicit) {
|
|
3209
|
-
|
|
3152
|
+
armWorkspacePublication(explicit.trigger, {
|
|
3210
3153
|
delayMs: message.retryAfterMs ?? 0,
|
|
3211
3154
|
requestId: explicit.requestId
|
|
3212
3155
|
});
|
|
3213
3156
|
} else if (message.status === "retry" || message.status === "failed" || workspaceConvergence.snapshot().dirtyGeneration > workspaceConvergence.snapshot().publishedGeneration) {
|
|
3214
|
-
|
|
3157
|
+
armWorkspacePublication(publication.trigger, { delayMs: message.retryAfterMs ?? 1e3 });
|
|
3215
3158
|
}
|
|
3216
3159
|
if (message.canonicalHead !== workspaceConvergence.snapshot().localHead) {
|
|
3217
3160
|
pendingWorkspaceHead = message.canonicalHead;
|
|
@@ -3259,11 +3202,11 @@ async function startWorker(options) {
|
|
|
3259
3202
|
pendingWorkspaceHead = workspaceConvergence.snapshot().desiredCanonicalHead;
|
|
3260
3203
|
void convergeAvailableWorkspaceHead();
|
|
3261
3204
|
}
|
|
3262
|
-
const explicit = !activeWorkspaceIncidentId ?
|
|
3205
|
+
const explicit = !activeWorkspaceIncidentId ? explicitWorkspacePublications.next() : void 0;
|
|
3263
3206
|
if (explicit) {
|
|
3264
|
-
|
|
3207
|
+
armWorkspacePublication(explicit.trigger, { delayMs: 0, requestId: explicit.requestId });
|
|
3265
3208
|
} else if (!activeWorkspaceIncidentId && workspaceConvergence.snapshot().dirtyGeneration > workspaceConvergence.snapshot().publishedGeneration) {
|
|
3266
|
-
|
|
3209
|
+
armWorkspacePublication({ type: "periodic", detail: "resume after workspace incident" }, { delayMs: 0 });
|
|
3267
3210
|
}
|
|
3268
3211
|
if (!activeWorkspaceIncidentId) schedulePendingManifestCheckoutHydration();
|
|
3269
3212
|
sendWorkspaceReady();
|
|
@@ -3364,10 +3307,8 @@ async function startWorker(options) {
|
|
|
3364
3307
|
});
|
|
3365
3308
|
return;
|
|
3366
3309
|
}
|
|
3367
|
-
const releaseWorkspaceWriter = targetMayMutateVisibleWorkspace(message.target) ? await workspaceFilesystemWriters.acquireWriter() : void 0;
|
|
3368
3310
|
const releaseWorkspaceMutation = await (0, import_workspace_command_sync_policy.acquireWorkspaceCommandMutation)(message.target, workspaceSyncSingleFlight);
|
|
3369
3311
|
let mutationLeaseTransferred = false;
|
|
3370
|
-
let writerLeaseTransferred = false;
|
|
3371
3312
|
try {
|
|
3372
3313
|
const resolvedTarget = resolveMessageTarget(message.target);
|
|
3373
3314
|
process.stdout.write(`[r5d-worker] pty ${message.ptyId}: ${describeWorkerSessionTarget(message.target)}
|
|
@@ -3380,16 +3321,11 @@ async function startWorker(options) {
|
|
|
3380
3321
|
...releaseWorkspaceMutation ? { releaseWorkspaceMutation } : {},
|
|
3381
3322
|
...targetMayMutateVisibleWorkspace(message.target) ? {
|
|
3382
3323
|
onTerminal: () => {
|
|
3383
|
-
markWorkspaceDirty(
|
|
3384
|
-
{ type: "process_terminal", detail: `pty ${message.ptyId} completed` },
|
|
3385
|
-
true
|
|
3386
|
-
);
|
|
3387
|
-
releaseWorkspaceWriter?.();
|
|
3324
|
+
markWorkspaceDirty({ type: "process_terminal", detail: `pty ${message.ptyId} completed` }, true);
|
|
3388
3325
|
}
|
|
3389
3326
|
} : {}
|
|
3390
3327
|
});
|
|
3391
3328
|
mutationLeaseTransferred = releaseWorkspaceMutation !== void 0;
|
|
3392
|
-
writerLeaseTransferred = releaseWorkspaceWriter !== void 0;
|
|
3393
3329
|
} catch (error) {
|
|
3394
3330
|
sendWorkerMessage(ws, {
|
|
3395
3331
|
type: "pty_error",
|
|
@@ -3399,7 +3335,6 @@ async function startWorker(options) {
|
|
|
3399
3335
|
});
|
|
3400
3336
|
} finally {
|
|
3401
3337
|
if (!mutationLeaseTransferred) releaseWorkspaceMutation?.();
|
|
3402
|
-
if (!writerLeaseTransferred) releaseWorkspaceWriter?.();
|
|
3403
3338
|
}
|
|
3404
3339
|
return;
|
|
3405
3340
|
}
|
|
@@ -3419,7 +3354,7 @@ async function startWorker(options) {
|
|
|
3419
3354
|
const activePty = activePtys.get(message.ptyId);
|
|
3420
3355
|
closePty(message);
|
|
3421
3356
|
if (activePty && targetMayMutateVisibleWorkspace(activePty.target)) {
|
|
3422
|
-
|
|
3357
|
+
armWorkspacePublication({ type: "process_terminal", detail: `pty ${message.ptyId} closed` }, { delayMs: 0 });
|
|
3423
3358
|
}
|
|
3424
3359
|
return;
|
|
3425
3360
|
}
|
|
@@ -3434,36 +3369,31 @@ async function startWorker(options) {
|
|
|
3434
3369
|
});
|
|
3435
3370
|
return;
|
|
3436
3371
|
}
|
|
3437
|
-
|
|
3372
|
+
let result;
|
|
3438
3373
|
try {
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
const resolvedTarget = resolveMessageTarget(message.target);
|
|
3443
|
-
process.stdout.write(`[r5d-worker] exec ${message.runId}: ${message.argv.join(" ")}
|
|
3374
|
+
const runCommand = async () => {
|
|
3375
|
+
const resolvedTarget = resolveMessageTarget(message.target);
|
|
3376
|
+
process.stdout.write(`[r5d-worker] exec ${message.runId}: ${message.argv.join(" ")}
|
|
3444
3377
|
`);
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
}
|
|
3465
|
-
} finally {
|
|
3466
|
-
releaseWorkspaceWriter?.();
|
|
3378
|
+
return await executeCommand({ message, resolvedTarget, baseUrl, token, artifactRoot, planRoot });
|
|
3379
|
+
};
|
|
3380
|
+
result = await (0, import_workspace_command_sync_policy.runWorkspaceCommand)(message.target, workspaceSyncSingleFlight, runCommand);
|
|
3381
|
+
} catch (error) {
|
|
3382
|
+
result = {
|
|
3383
|
+
type: "exec_result",
|
|
3384
|
+
requestId: message.requestId,
|
|
3385
|
+
stdout: "",
|
|
3386
|
+
stderr: "",
|
|
3387
|
+
exitCode: 1,
|
|
3388
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
ws.send(JSON.stringify(result));
|
|
3392
|
+
if (targetMayMutateVisibleWorkspace(message.target)) {
|
|
3393
|
+
markWorkspaceDirty(
|
|
3394
|
+
{ type: "shell_inline", sessionId: message.sessionId, processRunId: message.runId, detail: "foreground command completed" },
|
|
3395
|
+
true
|
|
3396
|
+
);
|
|
3467
3397
|
}
|
|
3468
3398
|
return;
|
|
3469
3399
|
}
|
|
@@ -3483,7 +3413,6 @@ async function startWorker(options) {
|
|
|
3483
3413
|
runId: message.runId
|
|
3484
3414
|
});
|
|
3485
3415
|
const runCommand = async () => {
|
|
3486
|
-
const releaseWorkspaceWriter = targetMayMutateVisibleWorkspace(message.target) ? await workspaceFilesystemWriters.acquireWriter() : void 0;
|
|
3487
3416
|
try {
|
|
3488
3417
|
const resolvedTarget = resolveMessageTarget(message.target);
|
|
3489
3418
|
process.stdout.write(`[r5d-worker] exec_start ${message.runId}: ${message.argv.join(" ")}
|
|
@@ -3509,7 +3438,6 @@ async function startWorker(options) {
|
|
|
3509
3438
|
true
|
|
3510
3439
|
);
|
|
3511
3440
|
}
|
|
3512
|
-
releaseWorkspaceWriter?.();
|
|
3513
3441
|
}
|
|
3514
3442
|
};
|
|
3515
3443
|
const execution = (0, import_workspace_command_sync_policy.runWorkspaceCommand)(message.target, workspaceSyncSingleFlight, runCommand);
|
|
@@ -3524,46 +3452,41 @@ async function startWorker(options) {
|
|
|
3524
3452
|
return;
|
|
3525
3453
|
}
|
|
3526
3454
|
if (message.type === "read" || message.type === "write" || message.type === "edit" || message.type === "grep" || message.type === "find" || message.type === "ls" || message.type === "view_file_bytes") {
|
|
3527
|
-
const releaseWorkspaceWriter = (message.type === "write" || message.type === "edit") && targetMayMutateVisibleWorkspace(message.target) ? await workspaceFilesystemWriters.acquireWriter() : void 0;
|
|
3528
3455
|
try {
|
|
3529
|
-
|
|
3530
|
-
const
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
|
|
3456
|
+
const result = await (0, import_workspace_command_sync_policy.runWorkspaceCommand)(message.target, workspaceSyncSingleFlight, async () => {
|
|
3457
|
+
const resolvedTarget = resolveMessageTarget(message.target);
|
|
3458
|
+
return await executeOperation({
|
|
3459
|
+
message,
|
|
3460
|
+
resolvedTarget,
|
|
3461
|
+
baseUrl,
|
|
3462
|
+
token,
|
|
3463
|
+
artifactRoot,
|
|
3464
|
+
planRoot
|
|
3465
|
+
});
|
|
3466
|
+
});
|
|
3467
|
+
ws.send(
|
|
3468
|
+
JSON.stringify({
|
|
3469
|
+
type: "operation_result",
|
|
3470
|
+
requestId: message.requestId,
|
|
3471
|
+
result
|
|
3472
|
+
})
|
|
3473
|
+
);
|
|
3474
|
+
if ((message.type === "write" || message.type === "edit") && targetMayMutateVisibleWorkspace(message.target)) {
|
|
3475
|
+
markWorkspaceDirty({
|
|
3476
|
+
type: message.type,
|
|
3477
|
+
sessionId: message.sessionId,
|
|
3478
|
+
toolCallId: message.requestId,
|
|
3479
|
+
...message.target.type === "project" ? { projectId: message.target.projectId, branchName: message.target.branchName } : {}
|
|
3540
3480
|
});
|
|
3541
|
-
ws.send(
|
|
3542
|
-
JSON.stringify({
|
|
3543
|
-
type: "operation_result",
|
|
3544
|
-
requestId: message.requestId,
|
|
3545
|
-
result
|
|
3546
|
-
})
|
|
3547
|
-
);
|
|
3548
|
-
if ((message.type === "write" || message.type === "edit") && targetMayMutateVisibleWorkspace(message.target)) {
|
|
3549
|
-
markWorkspaceDirty({
|
|
3550
|
-
type: message.type,
|
|
3551
|
-
sessionId: message.sessionId,
|
|
3552
|
-
toolCallId: message.requestId,
|
|
3553
|
-
...message.target.type === "project" ? { projectId: message.target.projectId, branchName: message.target.branchName } : {}
|
|
3554
|
-
});
|
|
3555
|
-
}
|
|
3556
|
-
} catch (error) {
|
|
3557
|
-
ws.send(
|
|
3558
|
-
JSON.stringify({
|
|
3559
|
-
type: "operation_result",
|
|
3560
|
-
requestId: message.requestId,
|
|
3561
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3562
|
-
})
|
|
3563
|
-
);
|
|
3564
3481
|
}
|
|
3565
|
-
}
|
|
3566
|
-
|
|
3482
|
+
} catch (error) {
|
|
3483
|
+
ws.send(
|
|
3484
|
+
JSON.stringify({
|
|
3485
|
+
type: "operation_result",
|
|
3486
|
+
requestId: message.requestId,
|
|
3487
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3488
|
+
})
|
|
3489
|
+
);
|
|
3567
3490
|
}
|
|
3568
3491
|
return;
|
|
3569
3492
|
}
|
|
@@ -3588,13 +3511,12 @@ async function startWorker(options) {
|
|
|
3588
3511
|
process.off("SIGTERM", handleGracefulShutdown);
|
|
3589
3512
|
process.off("SIGINT", handleGracefulShutdown);
|
|
3590
3513
|
stopHeartbeatWatchdog();
|
|
3591
|
-
if (
|
|
3592
|
-
clearTimeout(
|
|
3593
|
-
|
|
3514
|
+
if (workspacePublicationTimer) {
|
|
3515
|
+
clearTimeout(workspacePublicationTimer);
|
|
3516
|
+
workspacePublicationTimer = void 0;
|
|
3594
3517
|
}
|
|
3595
|
-
if (!
|
|
3596
|
-
|
|
3597
|
-
workspaceConvergence.resetTransientCheckpointState();
|
|
3518
|
+
if (!pendingPublication?.workInFlight) {
|
|
3519
|
+
workspaceConvergence.resetTransientPublicationState();
|
|
3598
3520
|
}
|
|
3599
3521
|
if (workspaceSafetyScan) {
|
|
3600
3522
|
clearInterval(workspaceSafetyScan);
|