@runfusion/fusion 0.75.1-beta.1 → 0.75.1-beta.2

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.
Files changed (117) hide show
  1. package/dist/bin.js +264 -136
  2. package/dist/child-process-worker.js +138 -38
  3. package/dist/client/.vite/manifest.json +253 -253
  4. package/dist/client/assets/{AgentDetailView-CE_7nvDT.js → AgentDetailView-ltOG8f0-.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-DYr3dk5X.js → AgentPermissionPolicyEditor-CC_rrbbG.js} +1 -1
  6. package/dist/client/assets/{AgentsView-DZoYoiaD.js → AgentsView-DWUdi27N.js} +3 -3
  7. package/dist/client/assets/{ChatView-BE9zMzYZ.js → ChatView-mFKfoegS.js} +1 -1
  8. package/dist/client/assets/{CommandCenter-DnLsp4_S.js → CommandCenter-C2wvDq_N.js} +1 -1
  9. package/dist/client/assets/{DevServerView-CI-3j-lH.js → DevServerView-0MWEJM7o.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-D1ADu0Av.js → DirectoryPicker-BjMPhCdh.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-CF8y1gob.js → DocumentsView-ckH3rjmd.js} +1 -1
  12. package/dist/client/assets/{EvalsView-C9vLiM2_.js → EvalsView-NyA644VF.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-CX_2Hjh0.js → ExperimentalAgentOnboardingModal-D0ZfbBRN.js} +1 -1
  14. package/dist/client/assets/{GoalsView-DJIA3k8q.js → GoalsView-Ctt5P_yo.js} +1 -1
  15. package/dist/client/assets/{InsightsView--TCeutLO.js → InsightsView-NDp0bdNB.js} +1 -1
  16. package/dist/client/assets/{MemoryView-Btp4m7pK.js → MemoryView-BKbA4Bm4.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-DXdfh-Uf.js → PiExtensionsManager-V3AFWMHm.js} +1 -1
  18. package/dist/client/assets/{PluginManager-BDFelFY6.js → PluginManager-D88G_TZh.js} +1 -1
  19. package/dist/client/assets/{PullRequestView-TSNKGSAg.js → PullRequestView-DQQmFFYC.js} +1 -1
  20. package/dist/client/assets/{ReportModal-DhXMNHDL.js → ReportModal-Clh1S8RF.js} +1 -1
  21. package/dist/client/assets/{ResearchView-0w30HikQ.js → ResearchView-kxvq4zp5.js} +1 -1
  22. package/dist/client/assets/SecretsView-Dm0Vk8SA.js +1 -0
  23. package/dist/client/assets/{SessionTerminal-CF6_uy2u.js → SessionTerminal-DJO4JTEX.js} +1 -1
  24. package/dist/client/assets/{SettingsModal-BMAPX_7v.js → SettingsModal-BN5mL_ym.js} +1 -1
  25. package/dist/client/assets/SettingsModal-CTf5voEW.js +21 -0
  26. package/dist/client/assets/{SettingsTextareaRow-LqXxpJl5.js → SettingsTextareaRow-CvKszqO-.js} +1 -1
  27. package/dist/client/assets/{SetupWizardModal-D1ZvGOcK.js → SetupWizardModal-D5hVZh1G.js} +2 -2
  28. package/dist/client/assets/{SkillsView-CfO5B7SO.js → SkillsView-DQVz21w2.js} +1 -1
  29. package/dist/client/assets/{WorkflowNodeEditor-CjdK9fFS.js → WorkflowNodeEditor-CpKIi6Tb.js} +1 -1
  30. package/dist/client/assets/{agent-import-generation-DqTzyLOZ.js → agent-import-generation-DGUNF3nd.js} +1 -1
  31. package/dist/client/assets/{architectureDiagram-3BPJPVTR-CHkolL_b.js → architectureDiagram-3BPJPVTR-CV83wubP.js} +1 -1
  32. package/dist/client/assets/{blockDiagram-GPEHLZMM-BFRYQi8H.js → blockDiagram-GPEHLZMM-CNQsA3dD.js} +1 -1
  33. package/dist/client/assets/{c4Diagram-AAUBKEIU-D9mMEYbR.js → c4Diagram-AAUBKEIU-CXe7ii5H.js} +1 -1
  34. package/dist/client/assets/channel-DoX862zl.js +1 -0
  35. package/dist/client/assets/{chunk-2J33WTMH-CCv6QaQn.js → chunk-2J33WTMH-BS6W9bWv.js} +1 -1
  36. package/dist/client/assets/{chunk-4BX2VUAB-Bfe22y5T.js → chunk-4BX2VUAB-DbehRhdW.js} +1 -1
  37. package/dist/client/assets/{chunk-55IACEB6-CwicrA9V.js → chunk-55IACEB6-DMI5SR42.js} +1 -1
  38. package/dist/client/assets/{chunk-727SXJPM-DlIpTC03.js → chunk-727SXJPM-D1d-GBVj.js} +1 -1
  39. package/dist/client/assets/{chunk-AQP2D5EJ-CRX4mFVq.js → chunk-AQP2D5EJ-BzO6K3Uf.js} +1 -1
  40. package/dist/client/assets/{chunk-FMBD7UC4-DzG-bovU.js → chunk-FMBD7UC4-BVRLV3lK.js} +1 -1
  41. package/dist/client/assets/{chunk-ND2GUHAM-D5F2jtpM.js → chunk-ND2GUHAM-DdWByQfn.js} +1 -1
  42. package/dist/client/assets/{chunk-QZHKN3VN-BmSaCwG6.js → chunk-QZHKN3VN-1ia12cRV.js} +1 -1
  43. package/dist/client/assets/classDiagram-4FO5ZUOK-mb2IeAGN.js +1 -0
  44. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-mb2IeAGN.js +1 -0
  45. package/dist/client/assets/{cose-bilkent-S5V4N54A-BbKTljui.js → cose-bilkent-S5V4N54A-BPDT41HR.js} +1 -1
  46. package/dist/client/assets/{dagre-BM42HDAG-u0hwXb_T.js → dagre-BM42HDAG-Cktn26EH.js} +1 -1
  47. package/dist/client/assets/{dashboard-view-BfYZZ9Ms.js → dashboard-view-8o0EUcRX.js} +1 -1
  48. package/dist/client/assets/{dashboard-view-faKSXA4_.js → dashboard-view-CkCerlVJ.js} +1 -1
  49. package/dist/client/assets/{dashboard-view-BjPZG2Fv.js → dashboard-view-D_HC4lnr.js} +1 -1
  50. package/dist/client/assets/{dashboard-view-oCjWDGbW.js → dashboard-view-zd8GxC49.js} +1 -1
  51. package/dist/client/assets/{diagram-2AECGRRQ-Q7towbBl.js → diagram-2AECGRRQ-But4Lvf-.js} +1 -1
  52. package/dist/client/assets/{diagram-5GNKFQAL-UAwBmAxb.js → diagram-5GNKFQAL-2bpQAGFc.js} +1 -1
  53. package/dist/client/assets/{diagram-KO2AKTUF-BL1n0pkf.js → diagram-KO2AKTUF-Ckn9Qd1u.js} +1 -1
  54. package/dist/client/assets/{diagram-LMA3HP47-O-v_IZUJ.js → diagram-LMA3HP47-Bjn8h84N.js} +1 -1
  55. package/dist/client/assets/{diagram-OG6HWLK6-CAYSE2Mz.js → diagram-OG6HWLK6-BI6541hx.js} +1 -1
  56. package/dist/client/assets/{erDiagram-TEJ5UH35-Cr_DgCyp.js → erDiagram-TEJ5UH35-BqMiwHiM.js} +1 -1
  57. package/dist/client/assets/{flowDiagram-I6XJVG4X-TdLzHKPW.js → flowDiagram-I6XJVG4X-Q_SAB10M.js} +1 -1
  58. package/dist/client/assets/{folder-open-BoddkTkv.js → folder-open-CHiAJbTN.js} +1 -1
  59. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CO1ErtJY.js → ganttDiagram-6RSMTGT7-CqWFSfPF.js} +1 -1
  60. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-C8_Kx0Yh.js → gitGraphDiagram-PVQCEYII-B1o4uEjO.js} +1 -1
  61. package/dist/client/assets/index-Bdw5eNKV.css +1 -0
  62. package/dist/client/assets/index-kwRywd9M.js +2767 -0
  63. package/dist/client/assets/{infoDiagram-5YYISTIA-Dd6Zo7Dh.js → infoDiagram-5YYISTIA-BzaMa0c2.js} +1 -1
  64. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-BE9JCLb5.js → ishikawaDiagram-YF4QCWOH-I38yge00.js} +1 -1
  65. package/dist/client/assets/{journeyDiagram-JHISSGLW-B6RIZGDq.js → journeyDiagram-JHISSGLW-WVQSgx4P.js} +1 -1
  66. package/dist/client/assets/{kanban-definition-UN3LZRKU-CPXff-h-.js → kanban-definition-UN3LZRKU-BWtPQ3AH.js} +1 -1
  67. package/dist/client/assets/{mermaid.core-CbGj7iEw.js → mermaid.core-D1hnBtbi.js} +4 -4
  68. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DF5LZmsH.js → mindmap-definition-RKZ34NQL-DqiSLkW7.js} +1 -1
  69. package/dist/client/assets/{pieDiagram-4H26LBE5-Dpy0Xm9T.js → pieDiagram-4H26LBE5-CcgwbdIN.js} +1 -1
  70. package/dist/client/assets/{puzzle-BZa4U8-N.js → puzzle-BhXUaTQl.js} +1 -1
  71. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-BTLAQFpz.js → quadrantDiagram-W4KKPZXB-MsqQQfDN.js} +1 -1
  72. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DSUV9ySs.js → requirementDiagram-4Y6WPE33-CILGjMMA.js} +1 -1
  73. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-Fmfn0XDL.js → sankeyDiagram-5OEKKPKP-c14fWbtR.js} +1 -1
  74. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-_343I_b4.js → sequenceDiagram-3UESZ5HK-BD5bxMom.js} +1 -1
  75. package/dist/client/assets/{shield-alert-CdJ55UvI.js → shield-alert-C9W2WywS.js} +1 -1
  76. package/dist/client/assets/{standing-instructions-template-r03dZ5Z0.js → standing-instructions-template-CJdbDSyg.js} +1 -1
  77. package/dist/client/assets/{stateDiagram-AJRCARHV-C9EbWegm.js → stateDiagram-AJRCARHV-CZ5YqeOn.js} +1 -1
  78. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-Bmh2GRh6.js → stateDiagram-v2-BHNVJYJU-mdMN-PNX.js} +1 -1
  79. package/dist/client/assets/{timeline-definition-PNZ67QCA-q86S9wyl.js → timeline-definition-PNZ67QCA-DHKay9uj.js} +1 -1
  80. package/dist/client/assets/{upload-DS9-qtCF.js → upload-DxEwowRU.js} +1 -1
  81. package/dist/client/assets/{users-DP5Sngeg.js → users-mNFgW_Zd.js} +1 -1
  82. package/dist/client/assets/{vennDiagram-CIIHVFJN-BFq8uIt3.js → vennDiagram-CIIHVFJN-X29K9hWM.js} +1 -1
  83. package/dist/client/assets/{wardley-L42UT6IY-BL_sLGYI.js → wardley-L42UT6IY-yEoTrfmN.js} +1 -1
  84. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-BEKJJ9Vi.js → wardleyDiagram-YWT4CUSO-ny4k3kG0.js} +1 -1
  85. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DsvFnlxK.js → xychartDiagram-2RQKCTM6-DC8ODtRJ.js} +1 -1
  86. package/dist/client/index.html +2 -2
  87. package/dist/client/version.json +1 -1
  88. package/dist/droid-cli/package.json +1 -1
  89. package/dist/extension.js +225 -93
  90. package/dist/pi-claude-cli/package.json +1 -1
  91. package/dist/plugin-sdk/index.d.ts +2 -1
  92. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  93. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  94. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  95. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  96. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  97. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  98. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  99. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  100. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  101. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  102. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  103. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  104. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  105. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  106. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  107. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  108. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  109. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  110. package/package.json +1 -1
  111. package/dist/client/assets/SecretsView-DgMu7279.js +0 -1
  112. package/dist/client/assets/SettingsModal-Dckls6LL.js +0 -21
  113. package/dist/client/assets/channel-CLdamWm5.js +0 -1
  114. package/dist/client/assets/classDiagram-4FO5ZUOK-BYWknNX0.js +0 -1
  115. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BYWknNX0.js +0 -1
  116. package/dist/client/assets/index-C7KY0q8Q.js +0 -2767
  117. package/dist/client/assets/index-DHk_s6rA.css +0 -1
@@ -1181,6 +1181,9 @@ function isFusionSiblingBranch(branch) {
1181
1181
  function resolveEffectiveAutoMerge(task, settings) {
1182
1182
  return task.autoMerge ?? settings.autoMerge;
1183
1183
  }
1184
+ function hasUserAutoMergeHold(task) {
1185
+ return task.autoMerge === false && task.autoMergeProvenance === "user";
1186
+ }
1184
1187
  function allowsAutoMergeProcessing(task, settings) {
1185
1188
  return (settings.autoMerge !== false || task.autoMerge === true) && !taskHasManualOpenPullRequest(task);
1186
1189
  }
@@ -63421,7 +63424,7 @@ function rowToTask(row) {
63421
63424
  executionStartBranch: row.executionStartBranch || void 0,
63422
63425
  branch: row.branch || void 0,
63423
63426
  autoMerge: row.autoMerge === null ? void 0 : row.autoMerge === 1,
63424
- autoMergeProvenance: row.autoMergeProvenance === "user" || row.autoMergeProvenance === "legacy-stamp" ? row.autoMergeProvenance : void 0,
63427
+ autoMergeProvenance: row.autoMergeProvenance === "user" || row.autoMergeProvenance === "mission" || row.autoMergeProvenance === "legacy-stamp" ? row.autoMergeProvenance : void 0,
63425
63428
  baseCommitSha: row.baseCommitSha || void 0,
63426
63429
  scopeOverride: row.scopeOverride ? true : void 0,
63427
63430
  scopeOverrideReason: row.scopeOverrideReason || void 0,
@@ -72937,10 +72940,10 @@ ${feature.acceptanceCriteria}`);
72937
72940
  Apply the selected Missions header workflow atomically during TaskStore.createTask so newly triaged features land in the intended workflow lane. Duplicate-guard reuses skip this create path, preserving existing duplicate tasks without workflow mutation.
72938
72941
  */
72939
72942
  /*
72940
- FNXC:MissionAutoMerge 2026-07-18-12:00:
72941
- An autoMerge:false mission stamps each newly triaged task so its shared branch produces one PR instead of per-task auto-merges. Duplicate reuse intentionally bypasses this create-only override.
72943
+ FNXC:MissionAutoMerge 2026-08-05-22:50:
72944
+ An autoMerge:false mission stamps each newly triaged task as mission policy so its shared branch produces one PR instead of per-task auto-merges. Duplicate reuse intentionally bypasses this create-only override; policy must not impersonate an operator manual-hold choice.
72942
72945
  */
72943
- ...mission?.autoMerge === false ? { autoMerge: false } : {},
72946
+ ...mission?.autoMerge === false ? { autoMerge: false, autoMergeProvenance: "mission" } : {},
72944
72947
  // FNXC:MissionTaskPrefix 2026-07-26-12:00: thread the mission's optional taskPrefix into TaskCreateInput for distributed id minting.
72945
72948
  ...mission?.taskPrefix ? { taskPrefix: mission.taskPrefix } : {},
72946
72949
  ...branchOptions?.workflowId !== void 0 ? { workflowId: branchOptions.workflowId } : {}
@@ -76118,10 +76121,10 @@ ${feature.acceptanceCriteria}`);
76118
76121
  }
76119
76122
  } : {},
76120
76123
  /*
76121
- FNXC:MissionAutoMerge 2026-07-18-12:00:
76122
- An autoMerge:false mission stamps each newly triaged task so its shared branch produces one PR instead of per-task auto-merges. Duplicate reuse intentionally bypasses this create-only override.
76124
+ FNXC:MissionAutoMerge 2026-08-05-22:50:
76125
+ An autoMerge:false mission stamps each newly triaged task as mission policy so its shared branch produces one PR instead of per-task auto-merges. Duplicate reuse intentionally bypasses this create-only override; policy must not impersonate an operator manual-hold choice.
76123
76126
  */
76124
- ...mission?.autoMerge === false ? { autoMerge: false } : {},
76127
+ ...mission?.autoMerge === false ? { autoMerge: false, autoMergeProvenance: "mission" } : {},
76125
76128
  // FNXC:MissionTaskPrefix 2026-07-26-12:00: thread the mission's optional taskPrefix into TaskCreateInput so the distributed allocator mints ERR-N (etc.) instead of the project prefix.
76126
76129
  ...mission?.taskPrefix ? { taskPrefix: mission.taskPrefix } : {},
76127
76130
  ...branchOptions?.workflowId !== void 0 ? { workflowId: branchOptions.workflowId } : {}
@@ -86472,7 +86475,9 @@ async function _createTaskInternalBackendImpl(store, input, title, resolvedWorkf
86472
86475
  sourceMetadata: withTaskBranchContextInSourceMetadata(input.source?.sourceMetadata, input.branchContext),
86473
86476
  branchContext: input.branchContext,
86474
86477
  autoMerge: input.autoMerge,
86475
- autoMergeProvenance: input.autoMerge === void 0 ? void 0 : "user",
86478
+ // FNXC:SharedBranchMemberHold 2026-08-05-22:50: trusted mission creation
86479
+ // preserves policy provenance; operator/API create requests retain user provenance.
86480
+ autoMergeProvenance: input.autoMerge === void 0 ? void 0 : input.autoMergeProvenance ?? "user",
86476
86481
  // FNXC:CodingIdeasWorkflow 2026-07-05-19:45: land the task in its
86477
86482
  // workflow's manual intake column (e.g. Coding (Ideas) → "ideas") when
86478
86483
  // no explicit column is given (main FN-7591 parity).
@@ -127350,6 +127355,7 @@ var init_task_timing = __esm({
127350
127355
  });
127351
127356
 
127352
127357
  // ../core/src/session-identity-registry.ts
127358
+ import { AsyncLocalStorage } from "node:async_hooks";
127353
127359
  import { resolve as resolve21 } from "node:path";
127354
127360
  import { realpathSync as realpathSync5 } from "node:fs";
127355
127361
  function getRegistry() {
@@ -127361,6 +127367,16 @@ function getRegistry() {
127361
127367
  }
127362
127368
  return registry3;
127363
127369
  }
127370
+ function getActiveInvocationStorage() {
127371
+ const holder = globalThis;
127372
+ const existing = holder[ACTIVE_INVOCATION_KEY];
127373
+ if (existing instanceof AsyncLocalStorage) {
127374
+ return existing;
127375
+ }
127376
+ const storage = new AsyncLocalStorage();
127377
+ holder[ACTIVE_INVOCATION_KEY] = storage;
127378
+ return storage;
127379
+ }
127364
127380
  function canonicalizeCwd(cwd) {
127365
127381
  const resolved = resolve21(cwd);
127366
127382
  try {
@@ -127388,8 +127404,13 @@ function registerFusionSessionIdentity(cwd, identity) {
127388
127404
  };
127389
127405
  }
127390
127406
  function resolveFusionSessionPrincipal(cwd) {
127407
+ const canonicalCwd = canonicalizeCwd(cwd);
127408
+ const activeInvocation = getActiveInvocationStorage().getStore();
127409
+ if (activeInvocation?.cwdKeys.has(canonicalCwd)) {
127410
+ return { kind: "agent", identity: activeInvocation.identity };
127411
+ }
127391
127412
  const registry3 = getRegistry();
127392
- const list = registry3.get(canonicalizeCwd(cwd));
127413
+ const list = registry3.get(canonicalCwd);
127393
127414
  if (!list || list.length === 0) {
127394
127415
  return { kind: "operator" };
127395
127416
  }
@@ -127398,14 +127419,24 @@ function resolveFusionSessionPrincipal(cwd) {
127398
127419
  }
127399
127420
  return { kind: "ambiguous", identities: [...list] };
127400
127421
  }
127422
+ function runWithFusionSessionIdentity(cwdKeys, identity, callback) {
127423
+ const invocation = {
127424
+ identity: { ...identity, registeredAt: Date.now() },
127425
+ cwdKeys: new Set(cwdKeys.map(canonicalizeCwd))
127426
+ };
127427
+ return getActiveInvocationStorage().run(invocation, callback);
127428
+ }
127401
127429
  function __clearFusionSessionIdentityRegistryForTests() {
127402
- globalThis[REGISTRY_KEY] = /* @__PURE__ */ new Map();
127430
+ const holder = globalThis;
127431
+ holder[REGISTRY_KEY] = /* @__PURE__ */ new Map();
127432
+ holder[ACTIVE_INVOCATION_KEY] = new AsyncLocalStorage();
127403
127433
  }
127404
- var REGISTRY_KEY;
127434
+ var REGISTRY_KEY, ACTIVE_INVOCATION_KEY;
127405
127435
  var init_session_identity_registry = __esm({
127406
127436
  "../core/src/session-identity-registry.ts"() {
127407
127437
  "use strict";
127408
127438
  REGISTRY_KEY = "__FUSION_SESSION_IDENTITY_REGISTRY_V1__";
127439
+ ACTIVE_INVOCATION_KEY = "__FUSION_SESSION_IDENTITY_ACTIVE_INVOCATION_V1__";
127409
127440
  }
127410
127441
  });
127411
127442
 
@@ -128376,6 +128407,7 @@ __export(src_exports, {
128376
128407
  hasRoleOverrides: () => hasRoleOverrides,
128377
128408
  hasSyncPassphraseConfigured: () => hasSyncPassphraseConfigured,
128378
128409
  hasTitleIdDrift: () => hasTitleIdDrift,
128410
+ hasUserAutoMergeHold: () => hasUserAutoMergeHold,
128379
128411
  hashWorkflowIr: () => hashWorkflowIr,
128380
128412
  healSchemaDrift: () => healSchemaDrift,
128381
128413
  importMcpServersJson: () => importMcpServersJson,
@@ -128836,6 +128868,7 @@ __export(src_exports, {
128836
128868
  runMemoryBackupCommand: () => runMemoryBackupCommand,
128837
128869
  runReconciliationAbort: () => runReconciliationAbort,
128838
128870
  runScheduledEvalBatch: () => runScheduledEvalBatch,
128871
+ runWithFusionSessionIdentity: () => runWithFusionSessionIdentity,
128839
128872
  sanitizeBranchSegment: () => sanitizeBranchSegment,
128840
128873
  sanitizeCliAgentSettings: () => sanitizeCliAgentSettings,
128841
128874
  sanitizeCliAgentsSettings: () => sanitizeCliAgentsSettings,
@@ -158234,6 +158267,7 @@ import { existsSync as existsSync49, readFileSync as readFileSync16, realpathSyn
158234
158267
  import { exec as exec11, execFile as execFile9 } from "node:child_process";
158235
158268
  import { promisify as promisify15 } from "node:util";
158236
158269
  import { createRequire as createRequire5 } from "node:module";
158270
+ import { randomUUID as randomUUID42 } from "node:crypto";
158237
158271
  import { basename as basename16, dirname as dirname24, join as join59, relative as relative8, isAbsolute as isAbsolute10, resolve as resolve30 } from "node:path";
158238
158272
  import {
158239
158273
  createAgentSession,
@@ -159938,7 +159972,8 @@ async function createFnAgent2(options) {
159938
159972
  });
159939
159973
  };
159940
159974
  const sessionIdentity = (() => {
159941
- const principalAgentId = options.actionGateContext?.agentId ?? options.permanentAgentGating?.requester?.actorId ?? "engine-session";
159975
+ const namedAgentId = options.actionGateContext?.agentId ?? options.permanentAgentGating?.requester?.actorId;
159976
+ const principalAgentId = namedAgentId ?? `engine-session-${randomUUID42()}`;
159942
159977
  const principalAgentName = options.actionGateContext?.agentName ?? options.permanentAgentGating?.requester?.actorName;
159943
159978
  return {
159944
159979
  agentId: principalAgentId,
@@ -159950,6 +159985,14 @@ async function createFnAgent2(options) {
159950
159985
  const sessionIdentityKeys = [...new Set([options.cwd, resolvedProjectRoot].filter((key) => Boolean(key)))];
159951
159986
  const attachSessionIdentity = (session) => {
159952
159987
  const identityDisposers = sessionIdentityKeys.map((key) => registerFusionSessionIdentity(key, sessionIdentity));
159988
+ const sessionInvocations = session;
159989
+ const wrapInvocation = (methodName) => {
159990
+ const original = sessionInvocations[methodName];
159991
+ if (typeof original !== "function") return;
159992
+ sessionInvocations[methodName] = (...args) => runWithFusionSessionIdentity(sessionIdentityKeys, sessionIdentity, () => original.apply(session, args));
159993
+ };
159994
+ wrapInvocation("prompt");
159995
+ wrapInvocation("promptWithFallback");
159953
159996
  const disposeBeforeIdentity = typeof session.dispose === "function" ? session.dispose.bind(session) : () => void 0;
159954
159997
  session.dispose = async () => {
159955
159998
  for (const disposeIdentity of identityDisposers) {
@@ -162745,10 +162788,11 @@ function createMergeAttemptHandler(deps) {
162745
162788
  );
162746
162789
  };
162747
162790
  }
162748
- function createMergeGateHandler() {
162791
+ function createMergeGateHandler(deps = {}) {
162749
162792
  return async (_node, ctx) => {
162750
162793
  const settingsAutoMerge = ctx.settings?.autoMerge;
162751
- const autoMerge = ctx.task.autoMerge !== false && settingsAutoMerge !== false;
162794
+ const settings = { autoMerge: settingsAutoMerge ?? true };
162795
+ const autoMerge = !hasUserAutoMergeHold(ctx.task) && (await deps.isLiveSharedBranchMember?.(ctx.task, settings) === true || ctx.task.autoMerge !== false && settings.autoMerge !== false);
162752
162796
  return {
162753
162797
  outcome: "success",
162754
162798
  value: autoMerge ? "auto-on" : "auto-off"
@@ -162758,6 +162802,7 @@ function createMergeGateHandler() {
162758
162802
  var init_merge_runner = __esm({
162759
162803
  "../engine/src/workflow-node-runners/merge-runner.ts"() {
162760
162804
  "use strict";
162805
+ init_src2();
162761
162806
  init_workflow_merge_nodes();
162762
162807
  }
162763
162808
  });
@@ -163101,7 +163146,7 @@ function createDefaultNodeHandlers(seams, runCustomNode, deps) {
163101
163146
  "parse-steps": parseSteps,
163102
163147
  code: createCodeNodeHandler(deps?.runCode),
163103
163148
  notify: createNotifyHandler(deps?.notifyDispatch),
163104
- "merge-gate": createMergeGateHandler(),
163149
+ "merge-gate": createMergeGateHandler({ isLiveSharedBranchMember: deps?.isLiveSharedBranchMember }),
163105
163150
  "merge-attempt": createMergeAttemptHandler({
163106
163151
  primitives: deps?.primitives,
163107
163152
  seams,
@@ -169712,7 +169757,7 @@ var init_goal_anchoring_audit = __esm({
169712
169757
  // ../engine/src/agent-tools.ts
169713
169758
  import { appendFile as appendFile3, mkdir as mkdir26, readFile as readFile34, readdir as readdir9, realpath, stat as stat9, writeFile as writeFile24 } from "node:fs/promises";
169714
169759
  import { existsSync as existsSync52 } from "node:fs";
169715
- import { createHash as createHash19, randomUUID as randomUUID42 } from "node:crypto";
169760
+ import { createHash as createHash19, randomUUID as randomUUID43 } from "node:crypto";
169716
169761
  import { tmpdir as tmpdir6 } from "node:os";
169717
169762
  import { extname as extname3, isAbsolute as isAbsolute13, join as join64, relative as relative11, resolve as resolve33, sep as sep9 } from "node:path";
169718
169763
  import { Type as Type2 } from "@earendil-works/pi-ai";
@@ -170358,7 +170403,7 @@ function createTaskCreateTool(store, provenance, options) {
170358
170403
  toType: "user",
170359
170404
  type: "agent-to-user",
170360
170405
  content: `Task proposal awaiting validation: ${title}`,
170361
- metadata: { kind: "task-proposal", proposalStatus: "pending", proposalIdempotencyKey: randomUUID42(), taskId: options.sourceTaskId, proposedTask: { title, description: params.description, priority: params.priority, workflowId: params.workflow_id, dependencies: params.dependencies } }
170406
+ metadata: { kind: "task-proposal", proposalStatus: "pending", proposalIdempotencyKey: randomUUID43(), taskId: options.sourceTaskId, proposedTask: { title, description: params.description, priority: params.priority, workflowId: params.workflow_id, dependencies: params.dependencies } }
170362
170407
  });
170363
170408
  return { content: [{ type: "text", text: "Task proposal submitted to the operator for validation; no task was created." }], details: { proposed: true } };
170364
170409
  }
@@ -194766,7 +194811,8 @@ var WorkflowGraphExecutor = class {
194766
194811
  parseSteps: deps.parseStepsDeps,
194767
194812
  runCode: deps.runCode,
194768
194813
  notifyDispatch: deps.notifyDispatch,
194769
- prNodes: deps.prNodes
194814
+ prNodes: deps.prNodes,
194815
+ isLiveSharedBranchMember: deps.isLiveSharedBranchMember
194770
194816
  }),
194771
194817
  ...deps.runnerRegistry?.toHandlers() ?? {},
194772
194818
  ...deps.handlers ?? {}
@@ -196009,6 +196055,10 @@ var WorkflowGraphTaskRunner = class {
196009
196055
  runCode: this.deps.runCode,
196010
196056
  notifyDispatch: this.deps.notifyDispatch,
196011
196057
  prNodes: this.deps.prNodes,
196058
+ // FNXC:SharedBranchMemberHold 2026-08-06-00:24: carry the executor's
196059
+ // live group resolver into the graph merge gate; omitting it turns
196060
+ // mission-policy members into manual holds before integration.
196061
+ isLiveSharedBranchMember: this.deps.isLiveSharedBranchMember,
196012
196062
  /*
196013
196063
  FNXC:WorkflowResume 2026-06-29-08:49:
196014
196064
  Production graph runs must fetch live task steps during foreach replay. The runner is the workflow boundary that has store access, so it supplies the fresh projection seam instead of making executor self-healing guess after a stale step node fails.
@@ -207415,16 +207465,29 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
207415
207465
  activeWork: await this.resolveActiveWorkColumnsFor(taskId, cache)
207416
207466
  };
207417
207467
  }
207418
- classifyPausedAbortWorkflowRecovery(task, settings, isExecuting, columns) {
207468
+ /*
207469
+ FNXC:SharedBranchMemberHold 2026-08-05-23:35:
207470
+ Pause-abort recovery must resolve the same live intermediate-group predicate as
207471
+ merge admission. Shared metadata alone is stale after group closure or a
207472
+ default-branch collision, so it cannot suppress that task's standalone hold.
207473
+ */
207474
+ async isLiveSharedMemberIntegration(task, settings) {
207475
+ const groupId = task.branchContext?.groupId?.trim();
207476
+ const group = groupId ? await this.store.getBranchGroup?.(groupId) : null;
207477
+ const defaultBranch = await resolveIntegrationBranch(this.options.rootDir, settings);
207478
+ return isLiveSharedBranchGroupMemberIntegration(task, group, defaultBranch);
207479
+ }
207480
+ async classifyPausedAbortWorkflowRecovery(task, settings, isExecuting, columns) {
207419
207481
  const isPausedAbortPark = task.status === "failed" && typeof task.error === "string" && task.error.includes(PAUSE_ABORT_PARK_OPERATOR_MARKER) && task.error.includes(PAUSE_ABORT_PARK_ERROR_MARKER);
207420
207482
  if (!isPausedAbortPark) return { kind: "no-action", reason: "not-pause-abort" };
207421
207483
  if (task.paused || task.userPaused || isExecuting) return { kind: "no-action", reason: "unsafe-or-not-routable" };
207422
207484
  const errorText = typeof task.error === "string" ? task.error.toLowerCase() : "";
207423
207485
  const isTerminalMergePark = errorText.includes("conflict") || errorText.includes("contamination") || errorText.includes("foreign") || errorText.includes("retry-exhausted") || errorText.includes("retries exhausted") || errorText.includes("max retries");
207424
207486
  const completedSteps = task.steps.length > 0 && task.steps.every((step) => step.status === "done" || step.status === "skipped");
207425
- const sharedBranchMember = isSharedBranchGroupMemberIntegration(task);
207426
- const hasReviewProgress = columns.review.has(task.column) && allowsAutoMergeProcessing(task, settings) && task.mergeDetails?.mergeConfirmed !== true && !isTerminalMergePark && completedSteps;
207427
- const hasManualMergeHoldProgress = columns.review.has(task.column) && (!allowsAutoMergeProcessing(task, settings) || resolveEffectiveAutoMerge(task, settings) === false) && !sharedBranchMember && task.mergeDetails?.mergeConfirmed !== true && !isTerminalMergePark && completedSteps;
207487
+ const liveSharedBranchMember = await this.isLiveSharedMemberIntegration(task, settings);
207488
+ const autoMergeProcessing = allowsAutoMergeProcessing(task, settings) || liveSharedBranchMember;
207489
+ const hasReviewProgress = columns.review.has(task.column) && autoMergeProcessing && task.mergeDetails?.mergeConfirmed !== true && !isTerminalMergePark && completedSteps;
207490
+ const hasManualMergeHoldProgress = columns.review.has(task.column) && (hasUserAutoMergeHold(task) || !allowsAutoMergeProcessing(task, settings) || resolveEffectiveAutoMerge(task, settings) === false) && (!liveSharedBranchMember || hasUserAutoMergeHold(task)) && task.mergeDetails?.mergeConfirmed !== true && !isTerminalMergePark && completedSteps;
207428
207491
  if (hasManualMergeHoldProgress) {
207429
207492
  return { kind: "work-item-resume", reason: "pause-abort-manual-merge-hold" };
207430
207493
  }
@@ -213092,8 +213155,23 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
213092
213155
  return own.length > 0 ? new Set(own) : /* @__PURE__ */ new Set(["in-review"]);
213093
213156
  };
213094
213157
  const executingIds = this.options.getExecutingTaskIds?.() ?? /* @__PURE__ */ new Set();
213158
+ const canRecoverMergeableReviewTask = async (task) => {
213159
+ if (hasUserAutoMergeHold(task)) return false;
213160
+ const groupId = task.branchContext?.groupId?.trim();
213161
+ const branchGroup = groupId ? await this.store.getBranchGroup(groupId) : null;
213162
+ const projectDefaultBranch = await resolveIntegrationBranch(this.options.rootDir, settings);
213163
+ if (isLiveSharedBranchGroupMemberIntegration(task, branchGroup, projectDefaultBranch)) {
213164
+ return true;
213165
+ }
213166
+ return allowsAutoMergeProcessing(task, settings) && resolveEffectiveAutoMerge(task, settings) !== false;
213167
+ };
213168
+ const mergeAdmission = await Promise.all(tasks2.map(async (task) => [
213169
+ task.id,
213170
+ await canRecoverMergeableReviewTask(task)
213171
+ ]));
213172
+ const mergeAdmissionByTaskId = new Map(mergeAdmission);
213095
213173
  const mergeable = tasks2.filter(
213096
- (t) => allowsAutoMergeProcessing(t, settings) && !t.paused && !executingIds.has(t.id) && t.status !== "failed" && // Exclude transient merge statuses. Active merges should be left alone;
213174
+ (t) => mergeAdmissionByTaskId.get(t.id) === true && !t.paused && !executingIds.has(t.id) && t.status !== "failed" && // Exclude transient merge statuses. Active merges should be left alone;
213097
213175
  // stale ones are handled by recoverStaleMergingStatus().
213098
213176
  t.status !== "merging" && t.status !== "merging-pr" && // FNXC:Workspace 2026-06-22-09:30 (Phase D U1, KTD1 — admit workspace tasks):
213099
213177
  // A workspace task has task.worktree===null (its worktrees live per-repo in
@@ -216140,7 +216218,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
216140
216218
  for (const t of tasks2) {
216141
216219
  if (!this.isPauseAbortParkCandidate(t)) continue;
216142
216220
  const columns = await this.resolvePauseAbortColumnsFor(t.id, columnCache);
216143
- if (this.classifyPausedAbortWorkflowRecovery(t, settings, executingIds.has(t.id), columns).kind !== "no-action") {
216221
+ if ((await this.classifyPausedAbortWorkflowRecovery(t, settings, executingIds.has(t.id), columns)).kind !== "no-action") {
216144
216222
  parked.push(t);
216145
216223
  }
216146
216224
  }
@@ -216157,7 +216235,7 @@ var SelfHealingManager = class _SelfHealingManager extends SelfHealingGitEvidenc
216157
216235
  continue;
216158
216236
  }
216159
216237
  const freshColumns = await this.resolvePauseAbortColumnsFor(fresh.id, columnCache);
216160
- const route = this.classifyPausedAbortWorkflowRecovery(fresh, settings, latestExecutingIds.has(fresh.id), freshColumns);
216238
+ const route = await this.classifyPausedAbortWorkflowRecovery(fresh, settings, latestExecutingIds.has(fresh.id), freshColumns);
216161
216239
  if (route.kind === "no-action") {
216162
216240
  continue;
216163
216241
  }
@@ -222882,6 +222960,7 @@ ${feedback}`,
222882
222960
  if (info.phase !== "pre-merge") return false;
222883
222961
  if (info.status !== "advisory_failure" && info.status !== "failed") return false;
222884
222962
  const liveTask = await this.store.getTask(taskId).catch(() => fallbackTask);
222963
+ if (hasUserAutoMergeHold(liveTask)) return false;
222885
222964
  const missingArtifactKeys = parseRequiredArtifactMissingValue(info.failureValue);
222886
222965
  if (missingArtifactKeys) {
222887
222966
  await this.recoverMissingRequiredArtifacts(liveTask, missingArtifactKeys, {
@@ -223138,6 +223217,7 @@ ${info.feedback}`, revisionKey),
223138
223217
  */
223139
223218
  async recoverFailedPreMergeWorkflowStep(task) {
223140
223219
  try {
223220
+ if (hasUserAutoMergeHold(task)) return false;
223141
223221
  const failed = (task.workflowStepResults ?? []).filter((r) => (r.phase || "pre-merge") === "pre-merge" && r.status === "failed").sort((a, b3) => {
223142
223222
  const aTs = Date.parse(a.completedAt || a.startedAt || "");
223143
223223
  const bTs = Date.parse(b3.completedAt || b3.startedAt || "");
@@ -223664,6 +223744,7 @@ ${info.feedback}`, revisionKey),
223664
223744
  getTask: (taskId) => this.store.getTask(taskId)
223665
223745
  },
223666
223746
  runId: resolvedRunId,
223747
+ isLiveSharedBranchMember: (nodeTask) => this.isLiveSharedBranchGroupMember(nodeTask),
223667
223748
  primitives: this.createAuthoritativeWorkflowPrimitives(settings),
223668
223749
  seams: this.createAuthoritativeWorkflowSeams(settings),
223669
223750
  prepareNodeExecution: (node, nodeTask, requirement) => this.prepareGraphNodeExecution(node, nodeTask, settings, requirement),
@@ -226605,6 +226686,7 @@ Graph value: ${failureValue}` : ""}`, budget.key),
226605
226686
  } catch {
226606
226687
  return false;
226607
226688
  }
226689
+ if (hasUserAutoMergeHold(live)) return false;
226608
226690
  const sharedBranchMember = await this.isLiveSharedBranchGroupMember(live);
226609
226691
  if (!sharedBranchMember && !allowsAutoMergeProcessing(live, settings)) return false;
226610
226692
  if (!sharedBranchMember && resolveEffectiveAutoMerge(live, settings) === false) return false;
@@ -226666,8 +226748,8 @@ Graph value: ${failureValue}` : ""}`, budget.key),
226666
226748
  } catch {
226667
226749
  return false;
226668
226750
  }
226669
- if (await this.isLiveSharedBranchGroupMember(live)) return false;
226670
- return !allowsAutoMergeProcessing(live, settings) || resolveEffectiveAutoMerge(live, settings) === false;
226751
+ if (await this.isLiveSharedBranchGroupMember(live) && !hasUserAutoMergeHold(live)) return false;
226752
+ return hasUserAutoMergeHold(live) || !allowsAutoMergeProcessing(live, settings) || resolveEffectiveAutoMerge(live, settings) === false;
226671
226753
  }
226672
226754
  async handleStaleInReviewPlanPauseAbortReplay(live, result, abortProvenance, pausedAborted, userCanceled, resumeLanesMemo) {
226673
226755
  if (!pausedAborted) return false;
@@ -226831,9 +226913,9 @@ Graph value: ${failureValue}` : ""}`, budget.key),
226831
226913
  if (settings.globalPause === true) return false;
226832
226914
  }
226833
226915
  if (live.column === resumeLanes.review) {
226834
- if (live.autoMerge === false) return false;
226835
226916
  if (!settings) return false;
226836
226917
  const sharedBranchMember = await this.isLiveSharedBranchGroupMember(live);
226918
+ if (hasUserAutoMergeHold(live) || live.autoMerge === false && !sharedBranchMember) return false;
226837
226919
  if (!sharedBranchMember && !allowsAutoMergeProcessing(live, settings)) return false;
226838
226920
  if (live.mergeDetails?.mergeConfirmed === true) return false;
226839
226921
  }
@@ -247890,6 +247972,7 @@ var InProcessRuntime = class extends EventEmitter27 {
247890
247972
  }
247891
247973
  }
247892
247974
  const prNodeGithubOps = this.config.prNodeGithubOps;
247975
+ const secretsStore = await this.taskStore.getSecretsStore();
247893
247976
  const executorOptions = {
247894
247977
  /*
247895
247978
  FNXC:PlanReviewLease 2026-07-26-21:12:
@@ -247905,6 +247988,7 @@ var InProcessRuntime = class extends EventEmitter27 {
247905
247988
  cliAgentRuntime: this.cliAgentRuntime?.bundle,
247906
247989
  pluginRunner: this.pluginRunner,
247907
247990
  messageStore: this.messageStore,
247991
+ secretsStore,
247908
247992
  missionStore,
247909
247993
  reflectionService,
247910
247994
  // PR-entity nodes (U3): assemble the handler deps from the CLI-injected
@@ -248006,6 +248090,7 @@ var InProcessRuntime = class extends EventEmitter27 {
248006
248090
  reflectionService,
248007
248091
  selfImproveService,
248008
248092
  credentialRotator: this.credentialRotator,
248093
+ secretsStore,
248009
248094
  snapshotManager: autoClaimSnapshotManager,
248010
248095
  onMissed: (agentId, reason) => {
248011
248096
  runtimeLog.warn(`Agent ${agentId} missed heartbeat: ${reason}`);
@@ -255045,7 +255130,21 @@ var ProjectEngine = class _ProjectEngine {
255045
255130
  Cleared on the first non-busy outcome (success path resets it).
255046
255131
  */
255047
255132
  workspaceBusyReenqueues = /* @__PURE__ */ new Map();
255133
+ workspaceBusyReenqueueTimers = /* @__PURE__ */ new Set();
255048
255134
  static WORKSPACE_BUSY_MAX_REENQUEUES = 10;
255135
+ /*
255136
+ FNXC:WorkspaceMergeDispatch 2026-08-05-23:56:
255137
+ Workspace lease-contention retries are engine-owned lifecycle work, not detached callbacks.
255138
+ Track only these busy re-enqueue timers so stop() can cancel them and tests can measure the
255139
+ capped workspace ladder without confusing it with merge-body or maintenance timers.
255140
+ */
255141
+ scheduleWorkspaceBusyReenqueue(taskId, delayMs) {
255142
+ const timer2 = setTimeout(() => {
255143
+ this.workspaceBusyReenqueueTimers.delete(timer2);
255144
+ if (!this.shuttingDown) this.internalEnqueueMerge(taskId);
255145
+ }, delayMs);
255146
+ this.workspaceBusyReenqueueTimers.add(timer2);
255147
+ }
255049
255148
  /**
255050
255149
  * Pending manual merge resolvers — keyed by taskId.
255051
255150
  * When `onMerge` is called, the task is enqueued like auto-merge but a
@@ -255580,6 +255679,10 @@ ${detail}`);
255580
255679
  clearInterval(this.mergeActiveReconcileTimer);
255581
255680
  this.mergeActiveReconcileTimer = null;
255582
255681
  }
255682
+ for (const timer2 of this.workspaceBusyReenqueueTimers) {
255683
+ clearTimeout(timer2);
255684
+ }
255685
+ this.workspaceBusyReenqueueTimers.clear();
255583
255686
  for (const [taskId, deferred] of this.capacityDeferredMerges) {
255584
255687
  clearTimeout(deferred.timer);
255585
255688
  for (const resolver of deferred.resolvers) {
@@ -256879,16 +256982,15 @@ ${detail}`);
256879
256982
  * older low-priority task would start before a later urgent one.
256880
256983
  */
256881
256984
  async allowInReviewMergeProcessing(task, settings, store = this.runtime.getTaskStore()) {
256882
- if (allowsAutoMergeProcessing(task, settings)) {
256883
- return true;
256884
- }
256985
+ if (hasUserAutoMergeHold(task)) return false;
256885
256986
  const groupId = task.branchContext?.groupId?.trim();
256886
256987
  const branchGroup = groupId ? await store.getBranchGroup?.(groupId) : null;
256887
- if (!branchGroup || branchGroup.status !== "open" || !branchGroup.branchName.trim()) {
256888
- return false;
256889
- }
256890
256988
  const projectDefaultBranch = await resolveIntegrationBranch(this.config.workingDirectory, settings);
256891
- return isLiveSharedBranchGroupMemberIntegration(task, branchGroup, projectDefaultBranch);
256989
+ if (isLiveSharedBranchGroupMemberIntegration(task, branchGroup, projectDefaultBranch)) {
256990
+ return true;
256991
+ }
256992
+ if (task.autoMerge === false && groupId) return false;
256993
+ return allowsAutoMergeProcessing(task, settings);
256892
256994
  }
256893
256995
  async emitLegacyAutoMergeStampAdvisory(store) {
256894
256996
  if (this.legacyAutoMergeStampAdvisoryEmitted) {
@@ -257841,9 +257943,7 @@ ${detail}`);
257841
257943
  runtimeLog.log(
257842
257944
  `Workspace land busy re-enqueue ${busyCount + 1}/${_ProjectEngine.WORKSPACE_BUSY_MAX_REENQUEUES} for ${taskId} in ${delayMs / 1e3}s (no mergeRetry consumed \u2014 pure lease contention)`
257843
257945
  );
257844
- setTimeout(() => {
257845
- if (!this.shuttingDown) this.internalEnqueueMerge(taskId);
257846
- }, delayMs);
257946
+ this.scheduleWorkspaceBusyReenqueue(taskId, delayMs);
257847
257947
  } else {
257848
257948
  this.workspaceBusyReenqueues.delete(taskId);
257849
257949
  await store.updateTask(taskId, { status: "failed", error: errorMsg }).catch(() => void 0);