@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/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: input.manifest?.repoHttpUrl ?? fallbackInternalRemoteUrl(input.baseUrl, input.projectId),
825
- authHeader: input.manifest?.repoAuthHeader ?? null,
826
- persistAuth: true,
827
- reconcileExistingOrigin: Boolean(input.manifest?.repoHttpUrl),
828
- requireRemoteBranch: false,
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
- if (hasWorktreeChanges(input.branchPath)) {
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 ensureBranchWorkspace(input) {
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 workspace = ensureBranchWorkspace({
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: workspace.branchPath, manifest };
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 workspaceCheckpointTimer;
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 pendingCheckpoint;
2419
- const explicitWorkspaceCheckpoints = new import_workspace_convergence.ExplicitWorkspaceCheckpointQueue();
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
- `[r5d-worker] failed to send workspace readiness: ${error instanceof Error ? error.message : String(error)}
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 armWorkspaceCheckpoint = (trigger, options2 = { delayMs: import_workspace_convergence.WORKSPACE_CHECKPOINT_QUIET_MS }) => {
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 && !explicitWorkspaceCheckpoints.schedule({ requestId: options2.requestId, trigger }, pendingCheckpoint?.requestId)) {
2465
+ if (options2.requestId && !explicitWorkspacePublications.schedule({ requestId: options2.requestId, trigger }, pendingPublication?.requestId)) {
2479
2466
  return;
2480
2467
  }
2481
- if (!options2.requestId && explicitWorkspaceCheckpoints.hasScheduled()) return;
2482
- if (workspaceCheckpointTimer) clearTimeout(workspaceCheckpointTimer);
2483
- workspaceCheckpointTimer = setTimeout(() => {
2484
- workspaceCheckpointTimer = void 0;
2485
- if (options2.requestId) explicitWorkspaceCheckpoints.consumeScheduled(options2.requestId);
2486
- if (currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) return;
2487
- if (!workspaceReady || !workspaceRemoteUrl) {
2488
- armWorkspaceCheckpoint(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
2489
- return;
2490
- }
2491
- if (activeWorkspaceIncidentId) {
2492
- workspaceConvergence.block();
2493
- sendWorkspaceReady();
2494
- if ((0, import_workspace_convergence.workspaceCheckpointIncidentAction)(options2.requestId) === "defer_automatic") return;
2495
- if (pendingCheckpoint) {
2496
- explicitWorkspaceCheckpoints.enqueue({ requestId: options2.requestId, trigger }, pendingCheckpoint.requestId);
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
- const snapshot2 = workspaceConvergence.snapshot();
2500
- pendingCheckpoint = {
2501
- requestId: options2.requestId,
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: snapshot2.dirtyGeneration,
2504
- explicit: true,
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: "workspace_checkpoint_request",
2515
- requestId: options2.requestId,
2535
+ type: "workspace_publication_request",
2536
+ requestId,
2516
2537
  trigger,
2517
- dirtyGeneration: snapshot2.dirtyGeneration,
2518
- localHead: snapshot2.localHead,
2519
- desiredCanonicalHead: snapshot2.desiredCanonicalHead
2538
+ dirtyGeneration: snapshot.dirtyGeneration,
2539
+ localHead: snapshot.localHead,
2540
+ desiredCanonicalHead: snapshot.desiredCanonicalHead
2520
2541
  })
2521
2542
  );
2522
2543
  } catch (error) {
2523
- pendingCheckpoint = void 0;
2544
+ pendingPublication = void 0;
2524
2545
  workspaceConvergence.defer();
2525
2546
  process.stderr.write(
2526
- `[r5d-worker] failed to request blocked workspace checkpoint authority: ${error instanceof Error ? error.message : String(error)}
2547
+ `[r5d-worker] failed to request workspace publication: ${error instanceof Error ? error.message : String(error)}
2527
2548
  `
2528
2549
  );
2529
- armWorkspaceCheckpoint(trigger, { delayMs: 1e3, requestId: options2.requestId });
2550
+ armWorkspacePublication(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
2530
2551
  }
2531
- return;
2532
- }
2533
- if (pendingCheckpoint || workerHasActiveWriter()) {
2534
- armWorkspaceCheckpoint(trigger, { delayMs: 1e3, ...options2.requestId ? { requestId: options2.requestId } : {} });
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
- armWorkspaceCheckpoint(trigger, { delayMs: force ? 0 : import_workspace_convergence.WORKSPACE_CHECKPOINT_QUIET_MS });
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 mayHydrateVisible = !workerHasActiveWriter() && !pendingCheckpoint && snapshot.dirtyGeneration === snapshot.publishedGeneration;
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 checkpoint" });
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 ensureVisibleWorkspaceCheckouts = (targets, options2 = {}) => {
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.requireRemoteBranch),
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
- workspaceManifestHydrationTimer = void 0;
2677
- if (!workspaceReady || !workspaceRemoteUrl || activeWorkspaceIncidentId || pendingCheckpoint || pendingManifestCheckouts.size === 0 || currentWorkerSocket !== ws || ws.readyState !== WebSocket.OPEN) {
2678
- if (pendingManifestCheckouts.size > 0 && currentWorkerSocket === ws && ws.readyState === WebSocket.OPEN) {
2679
- schedulePendingManifestCheckoutHydration(1e3);
2680
- }
2681
- return;
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
- const targets = [...pendingManifestCheckouts.values()];
2694
- ensureVisibleWorkspaceCheckouts(targets, { strictCanonicalRevalidation: true });
2695
- for (const target of targets) {
2696
- const manifest = manifestByProjectId.get(target.projectId);
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
- }).then(() => sendWorkspaceReady()).catch((error) => {
2704
- process.stderr.write(
2705
- `[r5d-worker] pending manifest checkout hydration failed: ${error instanceof Error ? error.message : String(error)}
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
- }).finally(() => {
2709
- releaseHydration();
2710
- workspaceManifestHydrationInFlight = false;
2711
- heartbeatBusyGrace = (0, import_heartbeat.grantWorkerHeartbeatBusyGrace)(lastServerHeartbeatAt, heartbeatBusyGrace);
2712
- if (pendingManifestCheckouts.size > 0) schedulePendingManifestCheckoutHydration(1e3);
2713
- });
2714
- }, Math.max(0, delayMs));
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 = ensureVisibleWorkspaceCheckouts(checkoutTargets, {
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.waitForWorkspaceCheckpointOnShutdown)({
2802
+ void (0, import_workspace_convergence.waitForWorkspacePublicationOnShutdown)({
2831
2803
  snapshot: () => workspaceConvergence.snapshot(),
2832
- forceCheckpoint: () => armWorkspaceCheckpoint({ type: "manual", detail: "graceful worker shutdown" }, { delayMs: 0 })
2804
+ forcePublication: () => armWorkspacePublication({ type: "manual", detail: "graceful worker shutdown" }, { delayMs: 0 })
2833
2805
  }).then((outcome) => {
2834
- process.stdout.write(`[r5d-worker] graceful workspace checkpoint ${outcome}
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 manifestAdmission = (0, import_workspace_manifest_admission.inspectWorkspaceManifestAdmission)({
2877
+ const manifestFilesystem = (0, import_workspace_manifest_admission.inspectWorkspaceManifestFilesystem)({
2906
2878
  projectsRoot,
2907
2879
  workspaceShadowRoot,
2908
2880
  projects: message.projects
2909
2881
  });
2910
- const releaseManifestHydration = await (0, import_workspace_manifest_admission.acquireWorkspaceManifestVisibleLease)(
2911
- workspaceFilesystemWriters,
2912
- manifestAdmission
2913
- );
2914
- let completed = false;
2915
- try {
2916
- completed = await workspaceSyncSingleFlight.runExclusive(async () => {
2917
- if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
2918
- const firstBootstrap = manifestAdmission.firstBootstrap;
2919
- configureGitHubAuth(message.githubCredential);
2920
- visibleGitIdentity = message.gitIdentity;
2921
- workspaceRemoteUrl = message.workspaceRemoteUrl;
2922
- const migratedProjectIds = releaseManifestHydration ? (0, import_managed_paths.migrateLegacyProjectRoots)(projectsRoot, message.projects) : [];
2923
- manifestByProjectId.clear();
2924
- for (const project of message.projects) manifestByProjectId.set(project.projectId, project);
2925
- const currentCheckouts = allManifestCheckouts();
2926
- const currentCheckoutKeys = new Set(
2927
- currentCheckouts.map(({ projectId, branchName }) => manifestCheckoutKey(projectId, branchName))
2928
- );
2929
- for (const key of pendingManifestCheckouts.keys()) {
2930
- if (!currentCheckoutKeys.has(key)) pendingManifestCheckouts.delete(key);
2931
- }
2932
- for (const checkout of currentCheckouts) {
2933
- const key = manifestCheckoutKey(checkout.projectId, checkout.branchName);
2934
- const branchPath = import_node_path.default.join(
2935
- projectRootFor(projectsRoot, checkout.projectId, manifestByProjectId),
2936
- checkout.branchName
2937
- );
2938
- if (!hasNormalVisibleGitDir(branchPath)) pendingManifestCheckouts.set(key, checkout);
2939
- }
2940
- if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
2941
- const created = releaseManifestHydration ? ensureVisibleWorkspaceCheckouts(currentCheckouts, { strictCanonicalRevalidation: true }) : [];
2942
- if (!workspaceManifestRevision.isCurrent(revisionToken)) return false;
2943
- const bootstrapped = await (0, import_workspace_sync.convergeWorkspaceHead)(
2944
- workspaceSyncInput({ type: "connect" }, { newVisibleCheckouts: created }),
2945
- {
2946
- // An existing checkout becomes routable after a fetch. Its
2947
- // visible tree converges asynchronously; first bootstrap alone
2948
- // must materialize the canonical snapshot before readiness.
2949
- // Re-check the incident immediately before convergence so a
2950
- // concurrently delivered fence forces fetch-only behavior.
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
- process.stdout.write(
2966
- `[r5d-worker] workspace manifest: ${message.projects.length} projects${migratedProjectIds.length > 0 ? `; migrated ${migratedProjectIds.length} project checkout root(s)` : ""}
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
- return true;
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 || pendingCheckpoint || workspaceSafetyScanInFlight) {
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 mayHydrateVisible = !workerHasActiveWriter() && before.dirtyGeneration === before.publishedGeneration;
2987
- const releaseVisibleHydration = mayHydrateVisible ? workspaceFilesystemWriters.tryAcquireCheckpoint() : null;
2988
- const hydrateVisible = releaseVisibleHydration !== null;
2989
- try {
2990
- const converged = await workspaceSyncSingleFlight.runExclusive(
2991
- () => (0, import_workspace_sync.convergeWorkspaceHead)(workspaceSyncInput({ type: "periodic", detail: "idle convergence scan" }), {
2992
- hydrateVisible
2993
- })
2994
- );
2995
- workspaceConvergence.observeCanonicalHead(converged.canonicalHead);
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
- armWorkspaceCheckpoint({ type: "periodic", detail: "resume dirty generation after reconnect" }, { delayMs: 0 });
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 === "workspace_checkpoint_now") {
3051
- armWorkspaceCheckpoint(message.trigger, { delayMs: 0, requestId: message.requestId });
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 === "workspace_checkpoint_authority") {
3055
- const checkpoint = pendingCheckpoint;
3056
- if (!checkpoint || checkpoint.requestId !== message.requestId) {
3057
- process.stderr.write(`[r5d-worker] ignoring checkpoint authority for unknown request ${message.requestId}
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
- checkpoint.releaseCheckpointAdmission();
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.resetTransientCheckpointState();
3020
+ workspaceConvergence.resetTransientPublicationState();
3071
3021
  workspaceConvergence.observeIncidentState(Boolean(activeWorkspaceIncidentId));
3072
3022
  if (message.status === "busy") {
3073
- armWorkspaceCheckpoint(checkpoint.trigger, {
3023
+ armWorkspacePublication(publication.trigger, {
3074
3024
  delayMs: message.retryAfterMs ?? 1e3,
3075
- requestId: checkpoint.requestId
3025
+ requestId: publication.requestId
3076
3026
  });
3077
3027
  } else if (!activeWorkspaceIncidentId) {
3078
- const explicit = explicitWorkspaceCheckpoints.next();
3028
+ const explicit = explicitWorkspacePublications.next();
3079
3029
  if (explicit) {
3080
- armWorkspaceCheckpoint(explicit.trigger, { delayMs: 0, requestId: explicit.requestId });
3030
+ armWorkspacePublication(explicit.trigger, { delayMs: 0, requestId: explicit.requestId });
3081
3031
  } else if (workspaceConvergence.snapshot().dirtyGeneration > workspaceConvergence.snapshot().publishedGeneration) {
3082
- armWorkspaceCheckpoint(checkpoint.trigger, { delayMs: 0 });
3032
+ armWorkspacePublication(publication.trigger, { delayMs: 0 });
3083
3033
  }
3084
3034
  }
3085
3035
  }
3086
3036
  sendWorkspaceReady();
3087
3037
  return;
3088
3038
  }
3089
- checkpoint.attemptId = message.attemptId;
3090
- checkpoint.authorityToken = message.authorityToken;
3091
- checkpoint.workInFlight = true;
3092
- pendingCheckpoint = checkpoint;
3093
- if (!checkpoint.admissionHeld) {
3094
- const releaseCheckpointAdmission = await workspaceFilesystemWriters.acquireCheckpoint();
3095
- if (currentWorkerSocket !== ws || pendingCheckpoint?.requestId !== checkpoint.requestId || pendingCheckpoint.attemptId !== message.attemptId) {
3096
- releaseCheckpointAdmission();
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 = ensureVisibleWorkspaceCheckouts(pendingTargets, { strictCanonicalRevalidation: true });
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(checkpoint.trigger, {
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: checkpoint.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: checkpoint.dirtyGeneration,
3154
- telemetry: (0, import_workspace_convergence.workspaceCheckpointTelemetry)({
3155
- requestedAt: checkpoint.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: "workspace_checkpoint_result",
3167
- requestId: checkpoint.requestId,
3110
+ type: "workspace_publication_result",
3111
+ requestId: publication.requestId,
3168
3112
  attemptId: message.attemptId,
3169
3113
  authorityToken: message.authorityToken,
3170
- dirtyGeneration: checkpoint.dirtyGeneration,
3114
+ dirtyGeneration: publication.dirtyGeneration,
3171
3115
  result
3172
3116
  })
3173
3117
  );
3174
3118
  } catch (error) {
3175
- workspaceConvergence.resetTransientCheckpointState();
3119
+ workspaceConvergence.resetTransientPublicationState();
3176
3120
  throw error;
3177
3121
  } finally {
3178
- checkpoint.workInFlight = false;
3179
- checkpoint.releaseCheckpointAdmission();
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 === "workspace_checkpoint_completed") {
3185
- const checkpoint = pendingCheckpoint;
3186
- if (!checkpoint || checkpoint.requestId !== message.requestId || checkpoint.attemptId !== message.attemptId) {
3187
- process.stderr.write(`[r5d-worker] ignoring completion for unknown checkpoint ${message.requestId}
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
- pendingCheckpoint = void 0;
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 ?? checkpoint.dirtyGeneration, checkpoint.dirtyGeneration),
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.resetTransientCheckpointState();
3146
+ workspaceConvergence.resetTransientPublicationState();
3204
3147
  workspaceConvergence.observeIncidentState(Boolean(activeWorkspaceIncidentId));
3205
3148
  }
3206
3149
  sendWorkspaceReady();
3207
- const explicit = message.status === "retry" && checkpoint.explicit ? { requestId: checkpoint.requestId, trigger: checkpoint.trigger } : explicitWorkspaceCheckpoints.next();
3150
+ const explicit = message.status === "retry" && publication.explicit ? { requestId: publication.requestId, trigger: publication.trigger } : explicitWorkspacePublications.next();
3208
3151
  if (explicit) {
3209
- armWorkspaceCheckpoint(explicit.trigger, {
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
- armWorkspaceCheckpoint(checkpoint.trigger, { delayMs: message.retryAfterMs ?? 1e3 });
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 ? explicitWorkspaceCheckpoints.next() : void 0;
3205
+ const explicit = !activeWorkspaceIncidentId ? explicitWorkspacePublications.next() : void 0;
3263
3206
  if (explicit) {
3264
- armWorkspaceCheckpoint(explicit.trigger, { delayMs: 0, requestId: explicit.requestId });
3207
+ armWorkspacePublication(explicit.trigger, { delayMs: 0, requestId: explicit.requestId });
3265
3208
  } else if (!activeWorkspaceIncidentId && workspaceConvergence.snapshot().dirtyGeneration > workspaceConvergence.snapshot().publishedGeneration) {
3266
- armWorkspaceCheckpoint({ type: "periodic", detail: "resume after workspace incident" }, { delayMs: 0 });
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
- armWorkspaceCheckpoint({ type: "process_terminal", detail: `pty ${message.ptyId} closed` }, { delayMs: 0 });
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
- const releaseWorkspaceWriter = targetMayMutateVisibleWorkspace(message.target) ? await workspaceFilesystemWriters.acquireWriter() : void 0;
3372
+ let result;
3438
3373
  try {
3439
- let result;
3440
- try {
3441
- const runCommand = async () => {
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
- return await executeCommand({ message, resolvedTarget, baseUrl, token, artifactRoot, planRoot });
3446
- };
3447
- result = await (0, import_workspace_command_sync_policy.runWorkspaceCommand)(message.target, workspaceSyncSingleFlight, runCommand);
3448
- } catch (error) {
3449
- result = {
3450
- type: "exec_result",
3451
- requestId: message.requestId,
3452
- stdout: "",
3453
- stderr: "",
3454
- exitCode: 1,
3455
- error: error instanceof Error ? error.message : String(error)
3456
- };
3457
- }
3458
- ws.send(JSON.stringify(result));
3459
- if (targetMayMutateVisibleWorkspace(message.target)) {
3460
- markWorkspaceDirty(
3461
- { type: "shell_inline", sessionId: message.sessionId, processRunId: message.runId, detail: "foreground command completed" },
3462
- true
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
- try {
3530
- const result = await workspaceSyncSingleFlight.runMutation(async () => {
3531
- const resolvedTarget = resolveMessageTarget(message.target);
3532
- return await executeOperation({
3533
- message,
3534
- resolvedTarget,
3535
- baseUrl,
3536
- token,
3537
- artifactRoot,
3538
- planRoot
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
- } finally {
3566
- releaseWorkspaceWriter?.();
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 (workspaceCheckpointTimer) {
3592
- clearTimeout(workspaceCheckpointTimer);
3593
- workspaceCheckpointTimer = void 0;
3514
+ if (workspacePublicationTimer) {
3515
+ clearTimeout(workspacePublicationTimer);
3516
+ workspacePublicationTimer = void 0;
3594
3517
  }
3595
- if (!pendingCheckpoint?.workInFlight) {
3596
- pendingCheckpoint?.releaseCheckpointAdmission();
3597
- workspaceConvergence.resetTransientCheckpointState();
3518
+ if (!pendingPublication?.workInFlight) {
3519
+ workspaceConvergence.resetTransientPublicationState();
3598
3520
  }
3599
3521
  if (workspaceSafetyScan) {
3600
3522
  clearInterval(workspaceSafetyScan);