@runfusion/fusion 0.77.0-beta.0 → 0.77.0-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 (138) hide show
  1. package/dist/bin.js +387 -72
  2. package/dist/child-process-worker.js +2479 -2196
  3. package/dist/client/.vite/manifest.json +262 -262
  4. package/dist/client/assets/{AgentDetailView-0G9qFd4j.js → AgentDetailView-Dew3af1O.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-BM68g7wo.js → AgentPermissionPolicyEditor-CxPQffiY.js} +1 -1
  6. package/dist/client/assets/{AgentsView-DkOUZWw4.js → AgentsView-Cr4LDGdt.js} +3 -3
  7. package/dist/client/assets/ChatView-cNYtYx05.js +13 -0
  8. package/dist/client/assets/{CommandCenter-DxRSFWNc.js → CommandCenter-DCC90LOP.js} +1 -1
  9. package/dist/client/assets/{DevServerView-DO-bqJFE.js → DevServerView-B5b520w6.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-Cp2gddTE.js → DirectoryPicker-1JvRd5mC.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-D0E-3G96.js → DocumentsView-ksK9f7xt.js} +1 -1
  12. package/dist/client/assets/{EvalsView-BoFVq5hw.js → EvalsView-a3LhgRSo.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-CS1Sdogm.js → ExperimentalAgentOnboardingModal-vdVa8h7F.js} +1 -1
  14. package/dist/client/assets/{GoalsView-sybf7JY4.js → GoalsView-Dz2o91fd.js} +1 -1
  15. package/dist/client/assets/{InsightsView-nHa7aShn.js → InsightsView-De3R_46d.js} +1 -1
  16. package/dist/client/assets/{MemoryView-D0IG44za.js → MemoryView-Cagk2wZG.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-CU76weJe.js → PiExtensionsManager-C9JABO_4.js} +1 -1
  18. package/dist/client/assets/{PluginManager-DyT8XbcG.js → PluginManager-D2csmdQa.js} +1 -1
  19. package/dist/client/assets/{PullRequestView-CnxWUSen.js → PullRequestView-DT8vTeVi.js} +1 -1
  20. package/dist/client/assets/{ReportModal-CMrmMQjD.js → ReportModal-YMP6V4vu.js} +1 -1
  21. package/dist/client/assets/{ResearchView-BTytQSgy.js → ResearchView-cNsjYu8F.js} +1 -1
  22. package/dist/client/assets/{SecretsView-BuSH5J87.js → SecretsView-BAmf7KyS.js} +1 -1
  23. package/dist/client/assets/{SessionTerminal-D04kYRrT.js → SessionTerminal-BjGcxq22.js} +1 -1
  24. package/dist/client/assets/{SettingsModal-Dm-ngbRr.js → SettingsModal-C_9RiEI7.js} +1 -1
  25. package/dist/client/assets/{SettingsModal-xSLhH7Tr.js → SettingsModal-DLfy2e_5.js} +4 -4
  26. package/dist/client/assets/{SettingsTextareaRow-CHPgocEp.js → SettingsTextareaRow-D8RHSj8b.js} +1 -1
  27. package/dist/client/assets/{SetupWizardModal-y88aXNIQ.js → SetupWizardModal-DRJ96pHQ.js} +2 -2
  28. package/dist/client/assets/{SkillsView-CYyQW1Hv.js → SkillsView-DyeCwYit.js} +1 -1
  29. package/dist/client/assets/{WorkflowNodeEditor-hYeoz1X8.js → WorkflowNodeEditor-C5Jc9w_A.js} +3 -3
  30. package/dist/client/assets/{agent-import-generation-CjiYXzCr.js → agent-import-generation-SCPNeF25.js} +1 -1
  31. package/dist/client/assets/{agentsOrgChartLayout-C0UP_X3z.js → agentsOrgChartLayout-CqKtNCjy.js} +1 -1
  32. package/dist/client/assets/{architectureDiagram-3BPJPVTR-Dd6GPcqM.js → architectureDiagram-3BPJPVTR-Cz2HYn0b.js} +1 -1
  33. package/dist/client/assets/{blockDiagram-GPEHLZMM-CC6pLxlz.js → blockDiagram-GPEHLZMM-IimJVscG.js} +1 -1
  34. package/dist/client/assets/{c4Diagram-AAUBKEIU-DxMP_l6y.js → c4Diagram-AAUBKEIU-C-xii7zn.js} +1 -1
  35. package/dist/client/assets/channel-D-UHgx8G.js +1 -0
  36. package/dist/client/assets/{chunk-2J33WTMH-BKYToL43.js → chunk-2J33WTMH-DQ-9Xccu.js} +1 -1
  37. package/dist/client/assets/{chunk-4BX2VUAB-Bg6rjQb3.js → chunk-4BX2VUAB-DmdAX9Bx.js} +1 -1
  38. package/dist/client/assets/{chunk-55IACEB6-CPUwbbGa.js → chunk-55IACEB6-IF2bk5IL.js} +1 -1
  39. package/dist/client/assets/{chunk-727SXJPM-DScQBCvv.js → chunk-727SXJPM-AeYpIzVu.js} +1 -1
  40. package/dist/client/assets/{chunk-AQP2D5EJ-DbX7uaXK.js → chunk-AQP2D5EJ-DV942DD9.js} +1 -1
  41. package/dist/client/assets/{chunk-FMBD7UC4-DvYKea1c.js → chunk-FMBD7UC4-Bt_riVlZ.js} +1 -1
  42. package/dist/client/assets/{chunk-ND2GUHAM-CH-Tvw7w.js → chunk-ND2GUHAM-CbyjNbXR.js} +1 -1
  43. package/dist/client/assets/{chunk-QZHKN3VN-CbyEvOoM.js → chunk-QZHKN3VN-DqiRniYQ.js} +1 -1
  44. package/dist/client/assets/classDiagram-4FO5ZUOK-Do-8MdAc.js +1 -0
  45. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Do-8MdAc.js +1 -0
  46. package/dist/client/assets/{cose-bilkent-S5V4N54A-BPB5fV3A.js → cose-bilkent-S5V4N54A-UCvthviL.js} +1 -1
  47. package/dist/client/assets/{dagre-BM42HDAG-CilYJ3rR.js → dagre-BM42HDAG-DnMlT1Oi.js} +1 -1
  48. package/dist/client/assets/{dashboard-view-dChSM_So.js → dashboard-view-C9D0aoRW.js} +1 -1
  49. package/dist/client/assets/dashboard-view-Cz0sp2Wl.js +1 -0
  50. package/dist/client/assets/{dashboard-view-DoLU6FxZ.js → dashboard-view-JysoyDRX.js} +1 -1
  51. package/dist/client/assets/{dashboard-view-DnVf3tmI.js → dashboard-view-myjM9tr8.js} +1 -1
  52. package/dist/client/assets/{diagram-2AECGRRQ-m9u1Qhyx.js → diagram-2AECGRRQ-BYFiqXGw.js} +1 -1
  53. package/dist/client/assets/{diagram-5GNKFQAL-DVr7Kf0N.js → diagram-5GNKFQAL-DZU3pSYq.js} +1 -1
  54. package/dist/client/assets/{diagram-KO2AKTUF-D7sgJDFx.js → diagram-KO2AKTUF-0ybdKuMm.js} +1 -1
  55. package/dist/client/assets/{diagram-LMA3HP47-DNKNDS6r.js → diagram-LMA3HP47-Rxbgnbsp.js} +1 -1
  56. package/dist/client/assets/{diagram-OG6HWLK6-1Bff4FWn.js → diagram-OG6HWLK6-BAU_hTeV.js} +1 -1
  57. package/dist/client/assets/{erDiagram-TEJ5UH35-DGua1UHN.js → erDiagram-TEJ5UH35-zr8HrwTt.js} +1 -1
  58. package/dist/client/assets/{flowDiagram-I6XJVG4X-UDfDtwsE.js → flowDiagram-I6XJVG4X-CrTw0iFw.js} +1 -1
  59. package/dist/client/assets/{folder-open-CteOypVk.js → folder-open-DnAlsXXn.js} +1 -1
  60. package/dist/client/assets/{ganttDiagram-6RSMTGT7-COdmD328.js → ganttDiagram-6RSMTGT7-CCORsxxz.js} +1 -1
  61. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-SUSls7Kw.js → gitGraphDiagram-PVQCEYII-C07wWSjj.js} +1 -1
  62. package/dist/client/assets/index-B_z7OKl4.js +2818 -0
  63. package/dist/client/assets/index-DPo-IAb2.css +1 -0
  64. package/dist/client/assets/{infoDiagram-5YYISTIA-e_DloXj7.js → infoDiagram-5YYISTIA-hAeccD_4.js} +1 -1
  65. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-DVWqihXg.js → ishikawaDiagram-YF4QCWOH-WLCzv-NH.js} +1 -1
  66. package/dist/client/assets/{journeyDiagram-JHISSGLW-BcPY-XP0.js → journeyDiagram-JHISSGLW-ClnasNhy.js} +1 -1
  67. package/dist/client/assets/{kanban-definition-UN3LZRKU-BCFG2Jle.js → kanban-definition-UN3LZRKU-CAuARhUz.js} +1 -1
  68. package/dist/client/assets/{mermaid.core-5yPje9Bi.js → mermaid.core-Bh02RvfX.js} +4 -4
  69. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DDApeT3K.js → mindmap-definition-RKZ34NQL-KNTlbW4V.js} +1 -1
  70. package/dist/client/assets/{pieDiagram-4H26LBE5-N61_jyeP.js → pieDiagram-4H26LBE5-BouAfBEw.js} +1 -1
  71. package/dist/client/assets/{puzzle-BkaCP30D.js → puzzle-CC8Ur3Cy.js} +1 -1
  72. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-C5qHiApF.js → quadrantDiagram-W4KKPZXB-wTdkCUJU.js} +1 -1
  73. package/dist/client/assets/{requirementDiagram-4Y6WPE33-C71okgzt.js → requirementDiagram-4Y6WPE33-BnjY4Tc_.js} +1 -1
  74. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-B2iKyLjB.js → sankeyDiagram-5OEKKPKP-C-QsS08u.js} +1 -1
  75. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DfdoYKKk.js → sequenceDiagram-3UESZ5HK-DD36MILE.js} +1 -1
  76. package/dist/client/assets/{shield-alert-BNSeDB8l.js → shield-alert-DcXc56Fy.js} +1 -1
  77. package/dist/client/assets/{standing-instructions-template-pZtzo1lK.js → standing-instructions-template-BF5y1BLz.js} +1 -1
  78. package/dist/client/assets/{stateDiagram-AJRCARHV-lS-sUi12.js → stateDiagram-AJRCARHV-WTq1wQr1.js} +1 -1
  79. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-DXJNDrV9.js → stateDiagram-v2-BHNVJYJU-eILJdjII.js} +1 -1
  80. package/dist/client/assets/{timeline-definition-PNZ67QCA-CCwvX81K.js → timeline-definition-PNZ67QCA-PRNwI0NR.js} +1 -1
  81. package/dist/client/assets/{upload-CDovVbu2.js → upload-qH_64O-B.js} +1 -1
  82. package/dist/client/assets/{useDiscoveredSkillsCache-BYqP-afh.js → useDiscoveredSkillsCache-C-GPCNaO.js} +1 -1
  83. package/dist/client/assets/{users-CTqECGLo.js → users-D2UesRE4.js} +1 -1
  84. package/dist/client/assets/{vennDiagram-CIIHVFJN-DaiR5nv9.js → vennDiagram-CIIHVFJN-CG2Z4T4O.js} +1 -1
  85. package/dist/client/assets/{wardley-L42UT6IY-hA5IHyPW.js → wardley-L42UT6IY-gO_fGvF9.js} +1 -1
  86. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-CILUNESc.js → wardleyDiagram-YWT4CUSO-BkyNpjUb.js} +1 -1
  87. package/dist/client/assets/{xychartDiagram-2RQKCTM6-72eNMmjz.js → xychartDiagram-2RQKCTM6-CMlZsiPq.js} +1 -1
  88. package/dist/client/index.html +2 -2
  89. package/dist/client/version.json +1 -1
  90. package/dist/droid-cli/package.json +1 -1
  91. package/dist/extension.js +345 -61
  92. package/dist/pi-claude-cli/package.json +1 -1
  93. package/dist/plugin-sdk/index.js +29 -2
  94. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +269 -16
  95. package/dist/plugins/fusion-plugin-acp-runtime/mcp-schema-server.cjs +171 -0
  96. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  97. package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +29 -2
  98. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  99. package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +29 -2
  100. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  101. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +29 -2
  102. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  103. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +29 -2
  104. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  105. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +29 -2
  106. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  107. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +29 -2
  108. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  109. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +29 -2
  110. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  111. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +29 -2
  112. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  113. package/dist/plugins/fusion-plugin-linear-import/bundled.js +29 -2
  114. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  115. package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +29 -2
  116. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  117. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +29 -2
  118. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  119. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +29 -2
  120. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  121. package/dist/plugins/fusion-plugin-quality/bundled.js +29 -2
  122. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  123. package/dist/plugins/fusion-plugin-reports/bundled.js +29 -2
  124. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  125. package/dist/plugins/fusion-plugin-roadmap/bundled.js +29 -2
  126. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  127. package/dist/plugins/fusion-plugin-todos/bundled.js +29 -2
  128. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  129. package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +29 -2
  130. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  131. package/package.json +1 -1
  132. package/dist/client/assets/ChatView-BPSm2JIH.js +0 -13
  133. package/dist/client/assets/channel-DlCEMoEf.js +0 -1
  134. package/dist/client/assets/classDiagram-4FO5ZUOK-Bc92O8Ks.js +0 -1
  135. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Bc92O8Ks.js +0 -1
  136. package/dist/client/assets/dashboard-view-BnGe8cWo.js +0 -1
  137. package/dist/client/assets/index-0ovTXt3t.css +0 -1
  138. package/dist/client/assets/index-DpCHwyiD.js +0 -2818
package/dist/bin.js CHANGED
@@ -16882,8 +16882,34 @@ function didFallBackToDefault(ir2) {
16882
16882
  async function resolveWorkflowIrForTaskWithProvenance(store, taskId, irCache, selectionCache) {
16883
16883
  let workflowId;
16884
16884
  try {
16885
- const selection = selectionCache?.has(taskId) ? selectionCache.get(taskId) : store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(taskId) : store.getTaskWorkflowSelection(taskId);
16886
- if (!selectionCache?.has(taskId)) selectionCache?.set(taskId, selection);
16885
+ const isSelectionCached = selectionCache?.has(taskId) ?? false;
16886
+ let selection = isSelectionCached && selectionCache ? selectionCache.get(taskId) : void 0;
16887
+ if (!isSelectionCached) {
16888
+ let inflight;
16889
+ let coalesced = false;
16890
+ if (selectionCache) {
16891
+ inflight = inflightSelectionReads.get(selectionCache);
16892
+ if (!inflight) {
16893
+ inflight = /* @__PURE__ */ new Map();
16894
+ inflightSelectionReads.set(selectionCache, inflight);
16895
+ }
16896
+ const pending = inflight.get(taskId);
16897
+ if (pending) {
16898
+ selection = await pending;
16899
+ coalesced = true;
16900
+ }
16901
+ }
16902
+ if (!coalesced) {
16903
+ const readPromise = store.getTaskWorkflowSelectionAsync ? store.getTaskWorkflowSelectionAsync(taskId) : Promise.resolve(store.getTaskWorkflowSelection(taskId));
16904
+ if (inflight) inflight.set(taskId, readPromise);
16905
+ try {
16906
+ selection = await readPromise;
16907
+ } finally {
16908
+ inflight?.delete(taskId);
16909
+ }
16910
+ }
16911
+ selectionCache?.set(taskId, selection);
16912
+ }
16887
16913
  workflowId = selection?.workflowId;
16888
16914
  } catch {
16889
16915
  return { ir: defaultCodingWorkflowIr(), source: "default" };
@@ -16907,13 +16933,14 @@ async function isTaskTerminalNodeIdAsync(store, taskId, nodeId) {
16907
16933
  }
16908
16934
  return nodeId === "end";
16909
16935
  }
16910
- var FELL_BACK_TO_DEFAULT;
16936
+ var inflightSelectionReads, FELL_BACK_TO_DEFAULT;
16911
16937
  var init_workflow_ir_resolver = __esm({
16912
16938
  "../core/src/workflows/workflow-ir-resolver.ts"() {
16913
16939
  "use strict";
16914
16940
  init_builtin_workflows();
16915
16941
  init_workflow_ir();
16916
16942
  init_workflow_prompt_overrides();
16943
+ inflightSelectionReads = /* @__PURE__ */ new WeakMap();
16917
16944
  FELL_BACK_TO_DEFAULT = /* @__PURE__ */ Symbol.for("fusion.workflowIr.fellBackToDefault");
16918
16945
  }
16919
16946
  });
@@ -36534,9 +36561,12 @@ async function markApprovalRequestCompleted(layer, requestId, input) {
36534
36561
  });
36535
36562
  }
36536
36563
  async function getApprovalAuditHistory(handle2, requestId, projectId2) {
36537
- const rows = await handle2.select().from(project_exports.approvalRequestAuditEvents).where(and(eq(project_exports.approvalRequestAuditEvents.requestId, requestId), projectScopeFor(project_exports.approvalRequestAuditEvents.projectId, projectId2))).orderBy(
36538
- sql`${project_exports.approvalRequestAuditEvents.createdAt} ASC, ${project_exports.approvalRequestAuditEvents.id} ASC`
36539
- );
36564
+ const eventType = project_exports.approvalRequestAuditEvents.eventType;
36565
+ const lifecycleRank = sql`CASE ${eventType} ${sql.join(
36566
+ APPROVAL_REQUEST_AUDIT_EVENT_TYPES.map((type, rank) => sql`WHEN ${type} THEN ${rank}`),
36567
+ sql` `
36568
+ )} ELSE ${APPROVAL_REQUEST_AUDIT_EVENT_TYPES.length} END`;
36569
+ const rows = await handle2.select().from(project_exports.approvalRequestAuditEvents).where(and(eq(project_exports.approvalRequestAuditEvents.requestId, requestId), projectScopeFor(project_exports.approvalRequestAuditEvents.projectId, projectId2))).orderBy(sql`${project_exports.approvalRequestAuditEvents.createdAt} ASC, ${lifecycleRank} ASC, ${project_exports.approvalRequestAuditEvents.id} ASC`);
36540
36570
  return rows.map((row) => rowToAuditEvent(row));
36541
36571
  }
36542
36572
  var init_async_approval_request_store = __esm({
@@ -140804,17 +140834,40 @@ var init_auth_storage = __esm({
140804
140834
  async getApiKey(provider, instance) {
140805
140835
  return resolveStoredCredentialApiKey(provider, instance ? this.getInstance(instance) : this.get(provider));
140806
140836
  }
140837
+ /*
140838
+ FNXC:ProviderAuth 2026-08-18-04:40:
140839
+ MODIFY MUST BE ABLE TO CREATE. This is the seam pi persists a COMPLETED LOGIN through
140840
+ (`Models.login` -> `credentials.modify(provider.id, ...)` in pi-ai's models.js), not just the seam
140841
+ it refreshes an existing token through.
140842
+
140843
+ It used to resolve its write target with `creating: false` and then bail —
140844
+ `if (!target || !this.credential(target, current)) return { changed: false }` — whenever the
140845
+ provider had no credential row yet. The callback was never invoked, nothing was written, and pi's
140846
+ login resolved as a SUCCESS. So a first-ever login for a provider could not be saved: the browser
140847
+ flow completed, the token exchange succeeded, the lock file was taken and released, `auth.json`
140848
+ stayed `{}`, and the dashboard's poll saw `authenticated: false` and reported the useless "Login
140849
+ did not complete. Please try again."
140850
+
140851
+ It looked provider-specific and environment-specific for the worst possible reason: it only
140852
+ reproduces on a store with NO existing row, so every developer and every long-lived install — where
140853
+ a row already exists and this path is a plain refresh — works flawlessly, while every fresh install
140854
+ (a new container, a new machine, a wiped `~/.fusion`) can never complete its first login.
140855
+
140856
+ Create when absent, update when present. A callback returning undefined still writes nothing, so
140857
+ pi's refresh-bails-out behaviour is unchanged.
140858
+ */
140807
140859
  async modify(provider, fn2) {
140808
140860
  this.assertRefFromKey(provider);
140809
140861
  return this.withLock(async (current) => {
140810
- const target = this.resolveWriteTarget(provider, current, false);
140811
- if (!target || !this.credential(target, current)) return { result: void 0, changed: false };
140812
- const next = await fn2(this.credential(target, current));
140862
+ const target = this.resolveWriteTarget(provider, current, true);
140863
+ if (!target) return { result: void 0, changed: false };
140864
+ const existing = this.credential(target, current);
140865
+ const next = await fn2(existing);
140813
140866
  if (next !== void 0) {
140814
140867
  current[formatProviderInstanceKey(target)] = next;
140815
140868
  return { result: next, changed: true };
140816
140869
  }
140817
- return { result: this.credential(target, current), changed: false };
140870
+ return { result: existing, changed: false };
140818
140871
  });
140819
140872
  }
140820
140873
  getOAuthProviders() {
@@ -140827,11 +140880,24 @@ var init_auth_storage = __esm({
140827
140880
  if (!this.modelRuntime) throw new Error("OAuth login requires a ModelRuntime-backed Fusion auth storage");
140828
140881
  const executionProvider = toExecutionModelProviderId(provider);
140829
140882
  const legacy = callbacks;
140830
- const interaction = { signal: legacy.signal, prompt: async (prompt) => legacy.onPrompt?.({ message: prompt.message, placeholder: "placeholder" in prompt ? prompt.placeholder : void 0 }) ?? "", notify: (event) => {
140831
- if (event.type === "auth_url") legacy.onAuth?.({ url: event.url, instructions: event.instructions });
140832
- else if (event.type === "device_code") legacy.onDeviceCode?.(event);
140833
- else if (event.type === "progress") legacy.onProgress?.(event.message);
140834
- } };
140883
+ const interaction = {
140884
+ signal: legacy.signal,
140885
+ prompt: async (prompt) => {
140886
+ if (prompt.type === "select") {
140887
+ const chosen = await legacy.onSelect?.({ message: prompt.message, options: prompt.options });
140888
+ return chosen ?? prompt.options[0]?.id ?? "";
140889
+ }
140890
+ if (prompt.type === "manual_code" && legacy.onManualCodeInput) {
140891
+ return await legacy.onManualCodeInput();
140892
+ }
140893
+ return await legacy.onPrompt?.({ message: prompt.message, placeholder: "placeholder" in prompt ? prompt.placeholder : void 0 }) ?? "";
140894
+ },
140895
+ notify: (event) => {
140896
+ if (event.type === "auth_url") legacy.onAuth?.({ url: event.url, instructions: event.instructions });
140897
+ else if (event.type === "device_code") legacy.onDeviceCode?.(event);
140898
+ else if (event.type === "progress") legacy.onProgress?.(event.message);
140899
+ }
140900
+ };
140835
140901
  await this.modelRuntime.login(executionProvider, "oauth", interaction);
140836
140902
  this.reload();
140837
140903
  }
@@ -144506,7 +144572,8 @@ var init_runtime_resolution = __esm({
144506
144572
  const result2 = await createFnAgent2({
144507
144573
  ...agentOptions,
144508
144574
  toolOutputMaxChars,
144509
- mcpServers: normalizeAgentRuntimeMcpServers(mcpServers)
144575
+ mcpServers: normalizeAgentRuntimeMcpServers(mcpServers),
144576
+ __rawPiSession: true
144510
144577
  });
144511
144578
  return {
144512
144579
  ...result2,
@@ -145696,6 +145763,7 @@ var init_agent_session_helpers = __esm({
145696
145763
  init_runtime_resolution();
145697
145764
  init_logger3();
145698
145765
  init_pi();
145766
+ init_pi();
145699
145767
  init_auth_storage();
145700
145768
  init_mock_provider();
145701
145769
  init_cli_provider_routing();
@@ -145703,6 +145771,12 @@ var init_agent_session_helpers = __esm({
145703
145771
  sessionLog = createLogger2("agent-session");
145704
145772
  mockRuntimeSingleton = new MockAgentRuntime();
145705
145773
  RUNTIMES_WITH_INTERNAL_TOOL_GATING = /* @__PURE__ */ new Set(["pi"]);
145774
+ try {
145775
+ registerRoutedAgentSessionFactory?.(
145776
+ createResolvedAgentSession
145777
+ );
145778
+ } catch {
145779
+ }
145706
145780
  }
145707
145781
  });
145708
145782
 
@@ -167249,7 +167323,49 @@ function withMcpPromptOptions(promptOptions, mcpServers) {
167249
167323
  }
167250
167324
  return { mcpServers };
167251
167325
  }
167326
+ function agentPluginRunnerRegistry() {
167327
+ return defaultAgentPluginRunners ??= /* @__PURE__ */ new Map();
167328
+ }
167329
+ function registerRoutedAgentSessionFactory(factory) {
167330
+ routedAgentSessionFactory = factory;
167331
+ }
167332
+ function registerDefaultAgentPluginRunner(rootDir, pluginRunner) {
167333
+ agentPluginRunnerRegistry().set(rootDir, pluginRunner);
167334
+ }
167335
+ function unregisterDefaultAgentPluginRunner(rootDir) {
167336
+ agentPluginRunnerRegistry().delete(rootDir);
167337
+ }
167338
+ function resolveDefaultAgentPluginRunner(cwd) {
167339
+ const registry3 = agentPluginRunnerRegistry();
167340
+ if (registry3.size === 0) return void 0;
167341
+ if (cwd) {
167342
+ let best;
167343
+ for (const [rootDir, runner] of registry3) {
167344
+ if ((cwd === rootDir || cwd.startsWith(`${rootDir}/`)) && (!best || rootDir.length > best.rootDir.length)) {
167345
+ best = { rootDir, runner };
167346
+ }
167347
+ }
167348
+ if (best) return best.runner;
167349
+ }
167350
+ if (registry3.size === 1) {
167351
+ return registry3.values().next().value;
167352
+ }
167353
+ return void 0;
167354
+ }
167252
167355
  async function createFnAgent2(options) {
167356
+ const { __rawPiSession, ...routableOptions } = options;
167357
+ if (!__rawPiSession && routedAgentSessionFactory) {
167358
+ const optionsWithRouting = routableOptions;
167359
+ const pluginRunner = optionsWithRouting.pluginRunner ?? resolveDefaultAgentPluginRunner(routableOptions.cwd);
167360
+ return routedAgentSessionFactory({
167361
+ ...routableOptions,
167362
+ sessionPurpose: routableOptions.sessionPurpose ?? "executor",
167363
+ ...pluginRunner ? { pluginRunner } : {}
167364
+ });
167365
+ }
167366
+ return createPiAgentSessionRaw(routableOptions);
167367
+ }
167368
+ async function createPiAgentSessionRaw(options) {
167253
167369
  piLog.debug(`createFnAgent called (tools=${options.tools}, provider=${options.defaultProvider}, model=${options.defaultModelId})`);
167254
167370
  const requestedMcpServers = options.mcpServers ?? [];
167255
167371
  const forwardedMcpServers = runtimeSupportsMcp("pi", options.defaultProvider) ? requestedMcpServers : [];
@@ -167806,7 +167922,7 @@ async function createFnAgent2(options) {
167806
167922
  settleFallbackDispatch: async () => void 0
167807
167923
  };
167808
167924
  }
167809
- var execAsync, RTK_ACCEPTED_REWRITE_EXIT_CODES, RTK_EXPECTED_PASSTHROUGH_EXIT_CODES, RTK_EXPECTED_FAIL_OPEN_ERROR_CODES, RTK_REWRITE_MAX_BUFFER_BYTES, hostExtensionPaths, FN_MEMORY_APPEND_TOOL_NAME, FUSION_SHUTDOWN_WRAP_FLAG, promptWithFallbackInFlight, COMPACTION_FALLBACK_INSTRUCTIONS, MAX_COMPACTED_PROMPT_MEMORY_CHARS, MAX_COMPACTED_SUBTASK_GUIDANCE_CHARS, MAX_COMPACTED_ATTACHMENTS_CHARS, MAX_COMPACTED_EXISTING_SPEC_CHARS, MAX_COMPACTED_TASK_PROMPT_CHARS, MAX_COMPACTED_USER_COMMENTS_CHARS, ModelFallbackExhaustedError, GATE_BYPASS_TOOL_NAMES, TOOL_OUTPUT_BUDGET_OVERRIDES;
167925
+ var execAsync, RTK_ACCEPTED_REWRITE_EXIT_CODES, RTK_EXPECTED_PASSTHROUGH_EXIT_CODES, RTK_EXPECTED_FAIL_OPEN_ERROR_CODES, RTK_REWRITE_MAX_BUFFER_BYTES, hostExtensionPaths, FN_MEMORY_APPEND_TOOL_NAME, FUSION_SHUTDOWN_WRAP_FLAG, promptWithFallbackInFlight, COMPACTION_FALLBACK_INSTRUCTIONS, MAX_COMPACTED_PROMPT_MEMORY_CHARS, MAX_COMPACTED_SUBTASK_GUIDANCE_CHARS, MAX_COMPACTED_ATTACHMENTS_CHARS, MAX_COMPACTED_EXISTING_SPEC_CHARS, MAX_COMPACTED_TASK_PROMPT_CHARS, MAX_COMPACTED_USER_COMMENTS_CHARS, ModelFallbackExhaustedError, GATE_BYPASS_TOOL_NAMES, TOOL_OUTPUT_BUDGET_OVERRIDES, routedAgentSessionFactory, defaultAgentPluginRunners;
167810
167926
  var init_pi = __esm({
167811
167927
  "../engine/src/pi.ts"() {
167812
167928
  "use strict";
@@ -178484,9 +178600,9 @@ function mergeParkedColumns(base, lanes) {
178484
178600
  terminal: /* @__PURE__ */ new Set([...base.terminal, ...lanes.terminal ?? [], complete, archived])
178485
178601
  };
178486
178602
  }
178487
- async function resolveTaskParkedColumns(store, taskId) {
178603
+ async function resolveTaskParkedColumns(store, taskId, selectionCache) {
178488
178604
  try {
178489
- const ir2 = await resolveWorkflowIrForTask(store, taskId);
178605
+ const ir2 = await resolveWorkflowIrForTask(store, taskId, void 0, selectionCache);
178490
178606
  const l = resolveLifecycleColumns(ir2);
178491
178607
  const complete = l?.complete ?? LEGACY_PARKED_COLUMNS2.complete;
178492
178608
  const archived = l?.archived ?? LEGACY_PARKED_COLUMNS2.archived;
@@ -178731,6 +178847,7 @@ var init_scheduler = __esm({
178731
178847
  }
178732
178848
  });
178733
178849
  this.store.on("task:moved", async ({ task, from, to: to2, source, lanes }) => {
178850
+ const movedSelectionCache = /* @__PURE__ */ new Map();
178734
178851
  this.lastAutoClaimFingerprint.set(task.id, computeAutoClaimFingerprint(task));
178735
178852
  const parked = mergeParkedColumns(LEGACY_PARKED_COLUMNS2, lanes);
178736
178853
  if (from === parked.hold || to2 === parked.hold) {
@@ -178786,7 +178903,7 @@ var init_scheduler = __esm({
178786
178903
  });
178787
178904
  }
178788
178905
  }
178789
- const resolvedParked = mergeParkedColumns(await resolveTaskParkedColumns(this.store, task.id), lanes);
178906
+ const resolvedParked = mergeParkedColumns(await resolveTaskParkedColumns(this.store, task.id, movedSelectionCache), lanes);
178790
178907
  if (resolvedParked.terminal.has(to2)) {
178791
178908
  try {
178792
178909
  const settings = await this.store.getSettings();
@@ -178852,6 +178969,7 @@ var init_scheduler = __esm({
178852
178969
  }
178853
178970
  });
178854
178971
  this.store.on("task:updated", (task, meta2) => {
178972
+ const updatedSelectionCache = /* @__PURE__ */ new Map();
178855
178973
  const nextFingerprint = computeAutoClaimFingerprint(task);
178856
178974
  const previousFingerprint = this.lastAutoClaimFingerprint.get(task.id);
178857
178975
  if (!previousFingerprint || previousFingerprint !== nextFingerprint) {
@@ -178882,7 +179000,7 @@ var init_scheduler = __esm({
178882
179000
  });
178883
179001
  }
178884
179002
  void (async () => {
178885
- const unpausedParked = await resolveTaskParkedColumns(this.store, task.id);
179003
+ const unpausedParked = await resolveTaskParkedColumns(this.store, task.id, updatedSelectionCache);
178886
179004
  if (this.running && unpausedParked.wake.has(task.column)) {
178887
179005
  schedulerLog.log(`Task ${task.id} unpaused \u2014 triggering scheduling`);
178888
179006
  void this.schedule();
@@ -178894,7 +179012,7 @@ var init_scheduler = __esm({
178894
179012
  } else if (this.planningTaskIds.has(task.id)) {
178895
179013
  this.planningTaskIds.delete(task.id);
178896
179014
  void (async () => {
178897
- const planningParked = await resolveTaskParkedColumns(this.store, task.id);
179015
+ const planningParked = await resolveTaskParkedColumns(this.store, task.id, updatedSelectionCache);
178898
179016
  if (this.running && !task.status && !task.paused && !task.userPaused && planningParked.wake.has(task.column)) {
178899
179017
  schedulerLog.log(`Task ${task.id} finished planning \u2014 triggering scheduling`);
178900
179018
  void this.schedule();
@@ -178907,7 +179025,7 @@ var init_scheduler = __esm({
178907
179025
  } else if (!task.status && !task.paused && !task.userPaused && (this.approvalHeldTaskIds.delete(task.id) || (Boolean(task.approvedPlanFingerprint) || task.workflowStepResults?.some(isPlanReviewSatisfied) === true) && !this.approvalReleasedTaskIds.has(task.id))) {
178908
179026
  this.approvalReleasedTaskIds.add(task.id);
178909
179027
  void (async () => {
178910
- const approvalParked = await resolveTaskParkedColumns(this.store, task.id);
179028
+ const approvalParked = await resolveTaskParkedColumns(this.store, task.id, updatedSelectionCache);
178911
179029
  if (this.running && !task.status && !task.paused && !task.userPaused && approvalParked.wake.has(task.column)) {
178912
179030
  schedulerLog.log(`Task ${task.id} plan approval cleared \u2014 triggering scheduling`);
178913
179031
  void this.schedule();
@@ -178946,7 +179064,8 @@ var init_scheduler = __esm({
178946
179064
  if (settings.globalPause || settings.enginePaused) {
178947
179065
  return;
178948
179066
  }
178949
- const deletedParked = await resolveTaskParkedColumns(this.store, task.id);
179067
+ const deletedSelectionCache = /* @__PURE__ */ new Map();
179068
+ const deletedParked = await resolveTaskParkedColumns(this.store, task.id, deletedSelectionCache);
178950
179069
  const deletedWipColumns = await resolveProjectColumnsForRoles(this.store, ["countsTowardWip"]);
178951
179070
  const todoTasks = await this.store.listTasks({ column: deletedParked.hold, slim: true });
178952
179071
  const inProgressById = /* @__PURE__ */ new Map();
@@ -179155,7 +179274,16 @@ var init_scheduler = __esm({
179155
179274
  }
179156
179275
  }
179157
179276
  async transitionQueuedEpisode(task, input) {
179158
- return (await this.store.transitionQueuedEpisode(task.id, input)).appended;
179277
+ if (typeof this.store.transitionQueuedEpisode === "function") {
179278
+ return (await this.store.transitionQueuedEpisode(task.id, input)).appended;
179279
+ }
179280
+ await this.store.updateTask(task.id, {
179281
+ status: "queued",
179282
+ blockedBy: input.blockedBy ?? null,
179283
+ overlapBlockedBy: input.overlapBlockedBy ?? null
179284
+ });
179285
+ await this.logDispatchQueuedReason(task.id, input.action);
179286
+ return true;
179159
179287
  }
179160
179288
  async logDispatchQueuedReason(taskId, reason, memoKey) {
179161
179289
  const key = `${taskId}:${memoKey ?? reason}`;
@@ -179207,13 +179335,14 @@ var init_scheduler = __esm({
179207
179335
  }
179208
179336
  async emitHighOverlapFanoutWarnings(tasks2) {
179209
179337
  const escalationIrCache = /* @__PURE__ */ new Map();
179338
+ const escalationSelectionCache = /* @__PURE__ */ new Map();
179210
179339
  const escalationByTaskId = /* @__PURE__ */ new Map();
179211
179340
  const escalationColumns = /* @__PURE__ */ new Set();
179212
179341
  const holdByTaskId = /* @__PURE__ */ new Map();
179213
179342
  const terminalByTaskId = /* @__PURE__ */ new Map();
179214
179343
  const blockerReviewColumns = /* @__PURE__ */ new Set();
179215
179344
  for (const task of tasks2) {
179216
- const ir2 = await resolveWorkflowIrForTask(this.store, task.id, escalationIrCache).catch(() => void 0);
179345
+ const ir2 = await resolveWorkflowIrForTask(this.store, task.id, escalationIrCache, escalationSelectionCache).catch(() => void 0);
179217
179346
  if (!ir2) continue;
179218
179347
  for (const id of columnsWithFlag(ir2, "countsTowardWip")) escalationColumns.add(id);
179219
179348
  for (const id of columnsWithFlag(ir2, "mergeOrchestration")) escalationColumns.add(id);
@@ -179283,9 +179412,10 @@ var init_scheduler = __esm({
179283
179412
  if (!agentStore) return;
179284
179413
  const runningAgents = await agentStore.listAgents({ state: "running", includeEphemeral: false });
179285
179414
  const linkedAgents = runningAgents.filter((agent) => agent.taskId === taskId);
179415
+ const rollbackSelectionCache = /* @__PURE__ */ new Map();
179286
179416
  for (const agent of linkedAgents) {
179287
179417
  const activeRun = await agentStore.getActiveHeartbeatRun?.(agent.id);
179288
- const rollbackParked = await resolveTaskParkedColumns(this.store, taskId);
179418
+ const rollbackParked = await resolveTaskParkedColumns(this.store, taskId, rollbackSelectionCache);
179289
179419
  const proof = evaluateParkedAgentTaskLink({
179290
179420
  agent,
179291
179421
  linkedTask: { column: rollbackParked.hold },
@@ -179333,11 +179463,12 @@ var init_scheduler = __esm({
179333
179463
  const repo = getCurrentRepo(this.store.getRootDir());
179334
179464
  if (!repo) return;
179335
179465
  const hydrationIrCache = /* @__PURE__ */ new Map();
179466
+ const hydrationSelectionCache = /* @__PURE__ */ new Map();
179336
179467
  for (const task of tasks2) {
179337
179468
  if (!task.prInfo) continue;
179338
179469
  let flags;
179339
179470
  try {
179340
- const ir2 = await resolveWorkflowIrForTask(this.store, task.id, hydrationIrCache);
179471
+ const ir2 = await resolveWorkflowIrForTask(this.store, task.id, hydrationIrCache, hydrationSelectionCache);
179341
179472
  const column = ir2.columns?.find((candidate) => candidate.id === task.column);
179342
179473
  if (column) flags = resolveColumnFlags(column);
179343
179474
  } catch {
@@ -180266,19 +180397,20 @@ var init_scheduler = __esm({
180266
180397
  return;
180267
180398
  }
180268
180399
  const sliceIdBeforeUpdate = feature.sliceId;
180269
- const featureSlice = await missionStore.getSlice(feature.sliceId);
180270
- const milestone = featureSlice ? await missionStore.getMilestone(featureSlice.milestoneId) : void 0;
180271
- const missionId = task.missionId ?? milestone?.missionId;
180272
- if (!missionId) {
180273
- schedulerLog.warn(`Task ${taskId} feature ${feature.id} has no resolvable mission; skipping reconciliation`);
180274
- return;
180275
- }
180276
- if (missionId !== task.missionId) {
180277
- try {
180400
+ let missionId = task.missionId;
180401
+ try {
180402
+ if (!missionId && typeof missionStore.getSlice === "function") {
180403
+ const featureSlice = await missionStore.getSlice(feature.sliceId);
180404
+ const milestone = featureSlice && typeof missionStore.getMilestone === "function" ? await missionStore.getMilestone(featureSlice.milestoneId) : void 0;
180405
+ missionId = milestone?.missionId;
180406
+ }
180407
+ if (!missionId) {
180408
+ schedulerLog.warn(`Task ${taskId} feature ${feature.id} has no resolvable mission; skipping reconciliation`);
180409
+ } else if (missionId !== task.missionId) {
180278
180410
  await reconcileMissionState({ taskStore: this.store, missionStore }, { missionId, source: "task-move" });
180279
- } catch (error3) {
180280
- schedulerLog.warn(`Mission reconciliation failed after resolving task ${taskId}; continuing mission completion handling:`, error3);
180281
180411
  }
180412
+ } catch (error3) {
180413
+ schedulerLog.warn(`Task ${taskId} feature ${feature.id} mission reconcile skipped (${String(error3)}); continuing to completion check`);
180282
180414
  }
180283
180415
  let completionFlags;
180284
180416
  try {
@@ -187947,7 +188079,6 @@ var init_notifier = __esm({
187947
188079
  }
187948
188080
  notifyGridlock(event) {
187949
188081
  if (event === null) {
187950
- this.lastGridlockNotificationAt = null;
187951
188082
  return;
187952
188083
  }
187953
188084
  if (!this.config.enabled || !this.config.topic || !this.isEventEnabled("gridlock")) return;
@@ -198763,6 +198894,63 @@ var init_agent_user_comments = __esm({
198763
198894
  }
198764
198895
  });
198765
198896
 
198897
+ // ../engine/src/git-identity.ts
198898
+ function slugifyAgentEmailLocalPart(value2) {
198899
+ return value2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
198900
+ }
198901
+ function resolveCommitIdentity(input = {}) {
198902
+ const { agent, settings } = input;
198903
+ if (settings?.commitAuthorEnabled === false) {
198904
+ return void 0;
198905
+ }
198906
+ const configuredName = settings?.commitAuthorName?.trim();
198907
+ const configuredEmail = settings?.commitAuthorEmail?.trim();
198908
+ if (configuredName && configuredEmail) {
198909
+ return { name: configuredName, email: configuredEmail };
198910
+ }
198911
+ const agentName = agent?.name?.trim() || agent?.id?.trim() || "";
198912
+ if (agentName) {
198913
+ const localPart = slugifyAgentEmailLocalPart(agentName);
198914
+ if (localPart) {
198915
+ return {
198916
+ name: configuredName || `${agentName} (Fusion)`,
198917
+ email: configuredEmail || `${localPart}@agents.fusion.local`
198918
+ };
198919
+ }
198920
+ }
198921
+ return {
198922
+ name: configuredName || FUSION_FALLBACK_IDENTITY.name,
198923
+ email: configuredEmail || FUSION_FALLBACK_IDENTITY.email
198924
+ };
198925
+ }
198926
+ function commitIdentityEnv(identity) {
198927
+ if (!identity) {
198928
+ return {};
198929
+ }
198930
+ return {
198931
+ GIT_AUTHOR_NAME: identity.name,
198932
+ GIT_AUTHOR_EMAIL: identity.email,
198933
+ GIT_COMMITTER_NAME: identity.name,
198934
+ GIT_COMMITTER_EMAIL: identity.email
198935
+ };
198936
+ }
198937
+ function commitIdentityArgs(identity) {
198938
+ if (!identity) {
198939
+ return [];
198940
+ }
198941
+ return ["-c", `user.name=${identity.name}`, "-c", `user.email=${identity.email}`];
198942
+ }
198943
+ var FUSION_FALLBACK_IDENTITY;
198944
+ var init_git_identity = __esm({
198945
+ "../engine/src/git-identity.ts"() {
198946
+ "use strict";
198947
+ FUSION_FALLBACK_IDENTITY = {
198948
+ name: "Fusion",
198949
+ email: "noreply@runfusion.ai"
198950
+ };
198951
+ }
198952
+ });
198953
+
198766
198954
  // ../engine/src/sandbox/bubblewrap-detect.ts
198767
198955
  import { exec as exec20 } from "node:child_process";
198768
198956
  import { promisify as promisify30 } from "node:util";
@@ -204000,8 +204188,12 @@ import { createHash as createHash29 } from "node:crypto";
204000
204188
  import { join as join73, resolve as resolve45 } from "node:path";
204001
204189
  import { hostname as hostname3 } from "node:os";
204002
204190
  import { Type as Type4 } from "typebox";
204003
- function mergerCommitEnv() {
204004
- return { ...process.env, [IDENTITY_GUARD_BYPASS_ENV]: "1" };
204191
+ function mergerCommitEnv(identity) {
204192
+ return {
204193
+ ...process.env,
204194
+ [IDENTITY_GUARD_BYPASS_ENV]: "1",
204195
+ ...commitIdentityEnv(identity ?? resolveCommitIdentity())
204196
+ };
204005
204197
  }
204006
204198
  async function resolveMergerLifecycleColumn(store, taskId, which) {
204007
204199
  const fallback2 = which === "complete" ? "done" : which === "merge" ? "in-review" : "todo";
@@ -211977,6 +212169,7 @@ var init_merger = __esm({
211977
212169
  init_worktree_hooks();
211978
212170
  init_effective_settings();
211979
212171
  init_agent_user_comments();
212172
+ init_git_identity();
211980
212173
  init_verification_utils();
211981
212174
  init_sandbox();
211982
212175
  init_verification_utils();
@@ -212172,7 +212365,7 @@ function hasTerminalInvalidDoneTransition(task) {
212172
212365
  function isPrincipalHeldPlanningStatusOwned(status) {
212173
212366
  return status === null || status === void 0;
212174
212367
  }
212175
- var log34, worktreeMetadataReconcileLog, yieldEventLoop2, DONE_TASK_INTEGRITY_SWEEP_LIMIT, BOARD_STALL_NOTIFICATION_COOLDOWN_MS, DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS, PHANTOM_EXECUTOR_BINDING_AGE_MULTIPLIER, MAX_NO_PROGRESS_RESUME_ATTEMPTS, PRE_EXECUTION_WORKTREE_MAX_IDLE_MS, APPROVED_TRIAGE_RECOVERY_GRACE_MS, STARVED_REFINEMENT_RECOVERY_GRACE_MS, STARVED_PEER_PROGRESS_THRESHOLD, STARVED_REFINEMENT_ESCALATION_COOLDOWN_MS, ORPHANED_EXECUTION_RECOVERY_GRACE_MS, STALLED_CARD_WATCHDOG_MS, LEAKED_WORKTREE_SLOT_GRACE_MS, NON_TERMINAL_STEP_STATUSES2, STRANDED_COMPLETED_TODO_ACTIVE_STATUSES, GHOST_REVIEW_PRESERVED_STATUSES, ORPHANED_WITH_WORKTREE_GRACE_MS, MAX_TASK_DONE_RETRIES, RECONCILE_SCOPE_OVERRIDE_MERGE_ACTIVE_STATUS_SET, MAX_STARVATION_DROPS, TERMINAL_WORKSPACE_WORKTREE_TEARDOWN_MIN_IDLE_MS, DEADLOCK_RECOVERY_COOLDOWN_MS, DEFAULT_STALE_MERGING_FANOUT_MIN_AGE_MS, DEFAULT_UNBACKED_MERGING_FANOUT_GRACE_MS, DURABLE_ERROR_RECOVERY_BASE_COOLDOWN_MS, DURABLE_ERROR_RECOVERY_MAX_COOLDOWN_MS, RUNNING_ON_INACTIVE_TASK_STALE_RUN_MS, UNREADABLE_WORKFLOW_SELECTION, SelfHealingManager;
212368
+ var log34, worktreeMetadataReconcileLog, yieldEventLoop2, DONE_METADATA_REPAIR_CAP, DONE_TASK_INTEGRITY_SWEEP_LIMIT, GIT_WORKTREE_CHURN_INTERVAL_MS, BOARD_STALL_NOTIFICATION_COOLDOWN_MS, DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS, PHANTOM_EXECUTOR_BINDING_AGE_MULTIPLIER, MAX_NO_PROGRESS_RESUME_ATTEMPTS, PRE_EXECUTION_WORKTREE_MAX_IDLE_MS, APPROVED_TRIAGE_RECOVERY_GRACE_MS, STARVED_REFINEMENT_RECOVERY_GRACE_MS, STARVED_PEER_PROGRESS_THRESHOLD, STARVED_REFINEMENT_ESCALATION_COOLDOWN_MS, ORPHANED_EXECUTION_RECOVERY_GRACE_MS, STALLED_CARD_WATCHDOG_MS, LEAKED_WORKTREE_SLOT_GRACE_MS, NON_TERMINAL_STEP_STATUSES2, STRANDED_COMPLETED_TODO_ACTIVE_STATUSES, GHOST_REVIEW_PRESERVED_STATUSES, ORPHANED_WITH_WORKTREE_GRACE_MS, MAX_TASK_DONE_RETRIES, RECONCILE_SCOPE_OVERRIDE_MERGE_ACTIVE_STATUS_SET, MAX_STARVATION_DROPS, TERMINAL_WORKSPACE_WORKTREE_TEARDOWN_MIN_IDLE_MS, DEADLOCK_RECOVERY_COOLDOWN_MS, DEFAULT_STALE_MERGING_FANOUT_MIN_AGE_MS, DEFAULT_UNBACKED_MERGING_FANOUT_GRACE_MS, DURABLE_ERROR_RECOVERY_BASE_COOLDOWN_MS, DURABLE_ERROR_RECOVERY_MAX_COOLDOWN_MS, RUNNING_ON_INACTIVE_TASK_STALE_RUN_MS, UNREADABLE_WORKFLOW_SELECTION, SelfHealingManager;
212176
212369
  var init_self_healing = __esm({
212177
212370
  "../engine/src/self-healing.ts"() {
212178
212371
  "use strict";
@@ -212235,7 +212428,9 @@ var init_self_healing = __esm({
212235
212428
  log34 = createLogger2("self-healing");
212236
212429
  worktreeMetadataReconcileLog = createLogger2("worktree-metadata-reconcile");
212237
212430
  yieldEventLoop2 = () => new Promise((resolve112) => setImmediateCb2(resolve112));
212431
+ DONE_METADATA_REPAIR_CAP = 25;
212238
212432
  DONE_TASK_INTEGRITY_SWEEP_LIMIT = 50;
212433
+ GIT_WORKTREE_CHURN_INTERVAL_MS = 60 * 60 * 1e3;
212239
212434
  BOARD_STALL_NOTIFICATION_COOLDOWN_MS = 60 * 6e4;
212240
212435
  DB_CORRUPTION_NOTIFICATION_COOLDOWN_MS = 60 * 60 * 1e3;
212241
212436
  PHANTOM_EXECUTOR_BINDING_AGE_MULTIPLIER = 3;
@@ -212291,7 +212486,10 @@ var init_self_healing = __esm({
212291
212486
  lastUnpauseAt = 0;
212292
212487
  // ── Maintenance timer ───────────────────────────────────────────────
212293
212488
  maintenanceInterval = null;
212489
+ maintenanceStarting = false;
212294
212490
  maintenanceRunning = false;
212491
+ /** Last wall-clock a batch-1 git-churn pass ran on this manager (coarse-cadence gate). */
212492
+ lastGitWorktreeChurnAt = 0;
212295
212493
  /** In-process belt only; the durable apply token remains the cross-process fence. */
212296
212494
  autoRecoverTerminalFailuresInFlight = false;
212297
212495
  // ── Event listener cleanup ──────────────────────────────────────────
@@ -213189,6 +213387,7 @@ var init_self_healing = __esm({
213189
213387
  }
213190
213388
  // ── Auto-unpause ───────────────────────────────────────────────────
213191
213389
  onSettingsUpdated(settings, previous) {
213390
+ this.syncMaintenanceOnRefresh(settings);
213192
213391
  if (!previous.globalPause && settings.globalPause) {
213193
213392
  if (!settings.autoUnpauseEnabled) {
213194
213393
  log34.log("Global pause activated \u2014 auto-unpause disabled, requires manual intervention");
@@ -213372,6 +213571,7 @@ var init_self_healing = __esm({
213372
213571
  try {
213373
213572
  await this.store.moveTask(taskId, await resolveReboundTargetForTask(this.store, taskId), {
213374
213573
  preserveProgress: true,
213574
+ preserveWorktree: true,
213375
213575
  preserveStatus: true,
213376
213576
  // #1411: backward recovery — skip order-derived adjacency.
213377
213577
  moveSource: "engine",
@@ -213452,7 +213652,23 @@ var init_self_healing = __esm({
213452
213652
  }
213453
213653
  // ── Periodic maintenance ──────────────────────────────────────────
213454
213654
  async startMaintenance() {
213655
+ if (this.maintenanceInterval) return;
213656
+ if (this.maintenanceStarting) return;
213657
+ this.maintenanceStarting = true;
213658
+ try {
213659
+ await this.armMaintenanceInternal();
213660
+ } finally {
213661
+ this.maintenanceStarting = false;
213662
+ }
213663
+ }
213664
+ async armMaintenanceInternal() {
213665
+ if (this.maintenanceInterval) return;
213455
213666
  const settings = await this.store.getSettings();
213667
+ if (this.maintenanceInterval) return;
213668
+ if (settings.globalPause || settings.enginePaused) {
213669
+ log34.debug("Periodic maintenance not armed \u2014 engine/global pause is active");
213670
+ return;
213671
+ }
213456
213672
  const intervalMs = settings.maintenanceIntervalMs ?? 9e5;
213457
213673
  if (intervalMs <= 0) {
213458
213674
  log34.debug("Periodic maintenance disabled (maintenanceIntervalMs <= 0)");
@@ -213463,6 +213679,38 @@ var init_self_healing = __esm({
213463
213679
  void this.runMaintenance();
213464
213680
  }, intervalMs);
213465
213681
  }
213682
+ /*
213683
+ * FNXC:PauseGatedMaintenance 2026-08-13-03:08 (RUFU-076):
213684
+ * Keep the periodic maintenance timer in sync with the engine/global pause state. `onSettingsUpdated`
213685
+ * calls this on every settings:updated event; pausing clears the armed timer (stopping the git churn),
213686
+ * unpausing (re)arms it idempotently via `startMaintenance`'s guard. This is the only writer of the
213687
+ * pause->stop-maintenance transition besides `stop()` teardown.
213688
+ */
213689
+ /*
213690
+ * FNXC:GitWorktreeChurnCadenceCoarsen 2026-08-13-04:05 (RUFU-076):
213691
+ * Coarse-cadence gate for batch-1 git-churn steps. Returns true only when a full coarse window
213692
+ * (hourly) has elapsed since the last batch-1 git-worktree pass, so an idle/healthy active project
213693
+ * does not re-run `git worktree prune` / `git worktree list` / `git branch` on every maintenance
213694
+ * interval. Note the shared timestamp also bounds cleanup-orphaned-branches and enforce-worktree-cap
213695
+ * even though they live further down batch-1.
213696
+ */
213697
+ isGitWorktreeChurnDue() {
213698
+ return Date.now() - this.lastGitWorktreeChurnAt >= GIT_WORKTREE_CHURN_INTERVAL_MS;
213699
+ }
213700
+ syncMaintenanceOnRefresh(settings) {
213701
+ const paused = settings.globalPause || settings.enginePaused;
213702
+ if (paused) {
213703
+ if (this.maintenanceInterval) {
213704
+ clearInterval(this.maintenanceInterval);
213705
+ this.maintenanceInterval = null;
213706
+ log34.debug("Periodic maintenance paused \u2014 cleared maintenance timer");
213707
+ }
213708
+ return;
213709
+ }
213710
+ if (!this.maintenanceInterval) {
213711
+ void this.startMaintenance();
213712
+ }
213713
+ }
213466
213714
  /*
213467
213715
  FNXC:CrossProcessDeleteObservation 2026-08-01-11:39:
213468
213716
  Periodic self-healing owns outbox retention. Each already-open PostgreSQL project is gated to
@@ -213799,17 +214047,26 @@ var init_self_healing = __esm({
213799
214047
  log34.debug("Maintenance cycle starting");
213800
214048
  try {
213801
214049
  const settings = await this.store.getSettings();
214050
+ const maintenancePaused = settings.globalPause || settings.enginePaused;
214051
+ const gitWorktreeChurnDue = this.isGitWorktreeChurnDue();
214052
+ if (!maintenancePaused && gitWorktreeChurnDue) {
214053
+ this.lastGitWorktreeChurnAt = Date.now();
214054
+ }
213802
214055
  const batch1Fns = [
213803
- { name: "prune-worktrees", fn: () => this.pruneWorktrees() },
214056
+ {
214057
+ name: "prune-worktrees",
214058
+ fn: () => maintenancePaused || !gitWorktreeChurnDue ? Promise.resolve(0) : this.pruneWorktrees()
214059
+ },
213804
214060
  {
213805
214061
  name: "prune-task-lifecycle-events",
213806
214062
  fn: async () => this.pruneTaskLifecycleEventsForMaintenance()
213807
214063
  },
213808
214064
  { name: "prune-github-check-states", fn: async () => this.pruneGitHubCheckStatesForMaintenance() },
213809
- { name: "cleanup-orphans", fn: () => this.cleanupOrphans() },
214065
+ { name: "cleanup-orphans", fn: () => maintenancePaused || !gitWorktreeChurnDue ? Promise.resolve(0) : this.cleanupOrphans() },
213810
214066
  {
213811
214067
  name: "cleanup-stale-temp-merge-worktrees",
213812
214068
  fn: async () => {
214069
+ if (maintenancePaused || !gitWorktreeChurnDue) return 0;
213813
214070
  const cleaned = await this.cleanupStaleTempMergeWorktrees();
213814
214071
  if (cleaned > 0) {
213815
214072
  log34.debug(`Cleaned ${cleaned} stale AI merge temp worktree(s)`);
@@ -213817,7 +214074,10 @@ var init_self_healing = __esm({
213817
214074
  return cleaned;
213818
214075
  }
213819
214076
  },
213820
- { name: "cleanup-orphaned-branches", fn: () => this.cleanupOrphanedBranches() },
214077
+ {
214078
+ name: "cleanup-orphaned-branches",
214079
+ fn: () => maintenancePaused || !gitWorktreeChurnDue ? Promise.resolve(0) : this.cleanupOrphanedBranches()
214080
+ },
213821
214081
  {
213822
214082
  name: "reconcile-orphaned-task-dirs",
213823
214083
  fn: async () => {
@@ -213925,7 +214185,7 @@ var init_self_healing = __esm({
213925
214185
  },
213926
214186
  { name: "fts-maintenance", fn: () => this.maintainTaskFts() },
213927
214187
  { name: "checkpoint-wal", fn: () => Promise.resolve(this.checkpointWal()) },
213928
- { name: "enforce-worktree-cap", fn: () => this.enforceWorktreeCap() }
214188
+ { name: "enforce-worktree-cap", fn: () => maintenancePaused || !gitWorktreeChurnDue ? Promise.resolve(0) : this.enforceWorktreeCap() }
213929
214189
  ];
213930
214190
  for (const fn2 of batch1Fns) {
213931
214191
  try {
@@ -215207,6 +215467,7 @@ var init_self_healing = __esm({
215207
215467
  moveSource: "engine",
215208
215468
  // #1411: backward recovery — skip order-derived adjacency.
215209
215469
  recoveryRehome: true,
215470
+ // worktree-discard-intended: reclaim proved the branch already merged / has zero unique commits; the checkout holds nothing worth keeping and worktree was explicitly nulled above.
215210
215471
  preserveProgress: true,
215211
215472
  preserveResumeState: true
215212
215473
  });
@@ -215297,6 +215558,7 @@ var init_self_healing = __esm({
215297
215558
  moveSource: "engine",
215298
215559
  // #1411: backward recovery — skip order-derived adjacency.
215299
215560
  recoveryRehome: true,
215561
+ // worktree-discard-intended: reclaim proved the branch already merged / has zero unique commits; the checkout holds nothing worth keeping and worktree was explicitly nulled above.
215300
215562
  preserveProgress: true,
215301
215563
  preserveResumeState: true
215302
215564
  });
@@ -216093,7 +216355,18 @@ var init_self_healing = __esm({
216093
216355
  const withUniqueWork = existingCandidates.filter((candidate) => candidate.aheadCount > 0);
216094
216356
  if (withUniqueWork.length === 1) {
216095
216357
  const selected = withUniqueWork[0];
216096
- const patch = { branch: selected.branch, worktree: null };
216358
+ let preservedWorktree = false;
216359
+ if (task.worktree && existsSync60(task.worktree)) {
216360
+ try {
216361
+ const { stdout } = await execAsync18("git rev-parse --abbrev-ref HEAD", {
216362
+ cwd: task.worktree,
216363
+ timeout: 3e4
216364
+ });
216365
+ preservedWorktree = stdout.trim() === selected.branch;
216366
+ } catch {
216367
+ }
216368
+ }
216369
+ const patch = preservedWorktree ? { branch: selected.branch } : { branch: selected.branch, worktree: null };
216097
216370
  if (!task.baseCommitSha) {
216098
216371
  const derivedBaseCommit = (await execAsync18(
216099
216372
  `git merge-base ${shellQuote2(integrationBase)} ${shellQuote2(selected.branch)}`,
@@ -216132,7 +216405,8 @@ var init_self_healing = __esm({
216132
216405
  aheadCount: selected.aheadCount,
216133
216406
  integrationBase,
216134
216407
  source: "auto-rebind-in-review",
216135
- previousBranch: task.branch ?? null
216408
+ previousBranch: task.branch ?? null,
216409
+ preservedWorktree
216136
216410
  }
216137
216411
  });
216138
216412
  result2.repaired++;
@@ -216142,7 +216416,8 @@ var init_self_healing = __esm({
216142
216416
  branch: selected.branch,
216143
216417
  aheadCount: selected.aheadCount,
216144
216418
  integrationBase,
216145
- previousBranch: task.branch ?? null
216419
+ previousBranch: task.branch ?? null,
216420
+ preservedWorktree
216146
216421
  });
216147
216422
  continue;
216148
216423
  }
@@ -217674,7 +217949,8 @@ var init_self_healing = __esm({
217674
217949
  */
217675
217950
  recoveryRehome: true,
217676
217951
  bypassGuards: true,
217677
- preserveProgress: true
217952
+ preserveProgress: true,
217953
+ preserveWorktree: true
217678
217954
  });
217679
217955
  rehomed += 1;
217680
217956
  await createRunAuditor(this.store, {
@@ -218312,7 +218588,7 @@ var init_self_healing = __esm({
218312
218588
  await this.emitBackwardMoveNoAction(task, "finalize-no-op-review", "task:finalize-no-op-review-no-action", proof);
218313
218589
  continue;
218314
218590
  }
218315
- await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, moveSource: "engine", recoveryRehome: true });
218591
+ await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, preserveWorktree: true, moveSource: "engine", recoveryRehome: true });
218316
218592
  continue;
218317
218593
  }
218318
218594
  const mergedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -218362,7 +218638,7 @@ var init_self_healing = __esm({
218362
218638
  baseRef: classification.baseRef,
218363
218639
  lane: "self-healing-finalize-no-op-review"
218364
218640
  });
218365
- await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, moveSource: "engine", recoveryRehome: true });
218641
+ await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, preserveWorktree: true, moveSource: "engine", recoveryRehome: true });
218366
218642
  recovered++;
218367
218643
  continue;
218368
218644
  }
@@ -218381,7 +218657,7 @@ var init_self_healing = __esm({
218381
218657
  classification: "proven-no-op",
218382
218658
  baseRef: classification.baseRef
218383
218659
  });
218384
- await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, moveSource: "engine", recoveryRehome: true });
218660
+ await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, preserveWorktree: true, moveSource: "engine", recoveryRehome: true });
218385
218661
  recovered++;
218386
218662
  continue;
218387
218663
  }
@@ -218924,7 +219200,7 @@ var init_self_healing = __esm({
218924
219200
  task.id,
218925
219201
  "Auto-recovered: in-review task still had incomplete steps \u2014 moved back to todo for retry"
218926
219202
  );
218927
- await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, moveSource: "engine", recoveryRehome: true });
219203
+ await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, preserveWorktree: true, moveSource: "engine", recoveryRehome: true });
218928
219204
  log34.log(`Recovered stale incomplete review task ${task.id}: moved back to todo`);
218929
219205
  recovered++;
218930
219206
  } catch (err) {
@@ -219318,7 +219594,7 @@ var init_self_healing = __esm({
219318
219594
  task.id,
219319
219595
  "Auto-recovered: in-review task idle past stuck-task timeout \u2014 kicked back to todo"
219320
219596
  );
219321
- await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, moveSource: "engine", recoveryRehome: true });
219597
+ await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, preserveWorktree: true, moveSource: "engine", recoveryRehome: true });
219322
219598
  log34.log(`Kicked ghost review task ${task.id} back to todo`);
219323
219599
  recovered++;
219324
219600
  } catch (err) {
@@ -220242,8 +220518,9 @@ var init_self_healing = __esm({
220242
220518
  return Boolean(task.baseCommitSha);
220243
220519
  });
220244
220520
  if (candidates.length === 0) return 0;
220521
+ const batch = candidates.slice(0, DONE_METADATA_REPAIR_CAP);
220245
220522
  let repaired = 0;
220246
- for (const task of candidates) {
220523
+ for (const task of batch) {
220247
220524
  if (isWorkspaceTask(task)) continue;
220248
220525
  if (task.mergeDetails?.landedFilesAttributionRestricted || task.mergeDetails?.noOpVerifiedShortCircuit) {
220249
220526
  log34.debug(`recoverDoneTaskMergeMetadata: skipped ${task.id} \u2014 attribution-restricted`);
@@ -221900,7 +222177,7 @@ var init_self_healing = __esm({
221900
222177
  nextRecoveryAt: new Date(Date.now() + delayMs).toISOString()
221901
222178
  },
221902
222179
  targetColumn: await resolveReboundTargetForTask(this.store, task.id),
221903
- moveOptions: { preserveProgress: true, moveSource: "engine" }
222180
+ moveOptions: { preserveProgress: true, preserveWorktree: true, moveSource: "engine" }
221904
222181
  });
221905
222182
  if (applied.outcome === "applied") {
221906
222183
  await this.store.logEntry(task.id, `Auto-recovered generic terminal failure (attempt ${claim.attempt}/${MAX_TERMINAL_FAILURE_AUTO_RETRIES})`);
@@ -222042,6 +222319,7 @@ var init_self_healing = __esm({
222042
222319
  if (route.kind === "node-requeue" && fresh.column !== requeueTarget) {
222043
222320
  await this.store.moveTask(task.id, requeueTarget, {
222044
222321
  preserveProgress: true,
222322
+ preserveWorktree: true,
222045
222323
  moveSource: "engine",
222046
222324
  recoveryRehome: true
222047
222325
  });
@@ -222275,6 +222553,7 @@ var init_self_healing = __esm({
222275
222553
  const leaseRecovered = await this.options.leaseManager.recoverAbandonedLease(
222276
222554
  task.id,
222277
222555
  `in-progress limbo: ${describeWorktreeState(task)} + null branch`,
222556
+ // worktree-discard-intended: limbo recovery — the worktree is already missing or its metadata cleared; there is no live checkout to hold.
222278
222557
  { preserveProgress: true }
222279
222558
  );
222280
222559
  if (!leaseRecovered) {
@@ -223460,7 +223739,7 @@ var init_self_healing = __esm({
223460
223739
  task.id,
223461
223740
  `Auto-retry ${nextCount}/${MAX_TASK_DONE_RETRIES}: agent finished without fn_task_done \u2014 requeuing to todo to resume partial work`
223462
223741
  );
223463
- await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, moveSource: "engine", recoveryRehome: true });
223742
+ await this.store.moveTask(task.id, await resolveReboundTargetForTask(this.store, task.id), { preserveProgress: true, preserveWorktree: true, moveSource: "engine", recoveryRehome: true });
223464
223743
  recovered++;
223465
223744
  } catch (err) {
223466
223745
  const errorMessage5 = err instanceof Error ? err.message : String(err);
@@ -261297,7 +261576,7 @@ async function ensureCommitTaskMetadata(mergeRoot, taskId, includeTaskId, traile
261297
261576
  const needsPrefix = includeTaskId && !subject.toLowerCase().startsWith(taskId.toLowerCase());
261298
261577
  const missingTrailers = trailers.filter((t) => !fullMessage.includes(t));
261299
261578
  if (!needsPrefix && missingTrailers.length === 0) return;
261300
- const args = ["-c", "trailer.ifExists=addIfDifferent", "commit", "--amend"];
261579
+ const args = [...commitIdentityArgs(resolveCommitIdentity()), "-c", "trailer.ifExists=addIfDifferent", "commit", "--amend"];
261301
261580
  if (needsPrefix) {
261302
261581
  args.push("-m", `${taskId}: ${subject}`);
261303
261582
  if (body.trim()) args.push("-m", body);
@@ -262932,6 +263211,7 @@ var execFileAsync25, aiMergeLog, MAX_CONCURRENT_ADVANCE_RETRIES, AiMergeBlockedE
262932
263211
  var init_merger_ai = __esm({
262933
263212
  "../engine/src/merge/merger-ai.ts"() {
262934
263213
  "use strict";
263214
+ init_git_identity();
262935
263215
  init_src2();
262936
263216
  init_agent_user_comments();
262937
263217
  init_worktree_names();
@@ -265710,7 +265990,7 @@ function defaultGitOps(cwd) {
265710
265990
  await runGit8(cwd, ["add", ...paths3]);
265711
265991
  },
265712
265992
  async commit(message) {
265713
- await runGit8(cwd, ["commit", "-m", JSON.stringify(message)]);
265993
+ await runGit8(cwd, [...commitIdentityArgs(resolveCommitIdentity()), "commit", "-m", JSON.stringify(message)]);
265714
265994
  return await runGit8(cwd, ["rev-parse", "HEAD"]);
265715
265995
  },
265716
265996
  async resetHard(ref) {
@@ -265788,6 +266068,7 @@ var execAsync55, GIT_TIMEOUT_MS10, GIT_MAX_BUFFER8;
265788
266068
  var init_git_ops = __esm({
265789
266069
  "../engine/src/experiment/git-ops.ts"() {
265790
266070
  "use strict";
266071
+ init_git_identity();
265791
266072
  init_finalize_types();
265792
266073
  execAsync55 = promisify81(exec59);
265793
266074
  GIT_TIMEOUT_MS10 = 3e4;
@@ -274280,6 +274561,7 @@ var init_in_process_runtime = __esm({
274280
274561
  "use strict";
274281
274562
  init_src2();
274282
274563
  init_scheduler();
274564
+ init_pi();
274283
274565
  init_executor();
274284
274566
  init_pr_nodes();
274285
274567
  init_src2();
@@ -274536,6 +274818,7 @@ var init_in_process_runtime = __esm({
274536
274818
  rootDir: this.config.workingDirectory
274537
274819
  });
274538
274820
  await this.pluginRunner.init();
274821
+ registerDefaultAgentPluginRunner(this.config.workingDirectory, this.pluginRunner);
274539
274822
  const projectScopedPluginMcpProvider = createProjectScopedPluginMcpProvider2(
274540
274823
  createRuntimePluginMcpProviderOptions({
274541
274824
  hostRootDir: this.config.workingDirectory,
@@ -275421,6 +275704,7 @@ var init_in_process_runtime = __esm({
275421
275704
  );
275422
275705
  }
275423
275706
  if (this.pluginRunner) {
275707
+ unregisterDefaultAgentPluginRunner(this.config.workingDirectory);
275424
275708
  await this.pluginRunner.shutdown();
275425
275709
  runtimeLog.log("PluginRunner shutdown complete");
275426
275710
  }
@@ -294517,6 +294801,8 @@ async function createMissionInterviewAgent(session, rootDir, store, promptOverri
294517
294801
  tools: "readonly",
294518
294802
  mcpServers,
294519
294803
  allowMcpToolsInReadonly: true,
294804
+ // FNXC:MissionInterviewRuntimeResolution 2026-08-16-14:37: forward the plugin runner so the shared seam can route CLI-runtime model selections (cursor/claude/grok/omp/hermes) to their runtime plugins.
294805
+ ...pluginRunner ? { pluginRunner } : {},
294520
294806
  ...skillContext.skillSelectionContext ? { skillSelection: skillContext.skillSelectionContext } : {},
294521
294807
  builtinToolsAllowlist: [...MISSION_INTERVIEW_BUILTIN_WEB_TOOLS],
294522
294808
  customTools: [...createPlanningBoardTools(store)],
@@ -294637,7 +294923,8 @@ async function ensureMissionInterviewAgent(session, rootDir, store, historyForRe
294637
294923
  if (abortSignal.aborted) {
294638
294924
  throw createAbortError3();
294639
294925
  }
294640
- await session.agent.session.prompt(
294926
+ await promptWithFallback(
294927
+ session.agent.session,
294641
294928
  [
294642
294929
  "Previous conversation summary:",
294643
294930
  historySummary,
@@ -294689,7 +294976,7 @@ async function continueAgentConversation2(session, message) {
294689
294976
  if (abortSignal.aborted) {
294690
294977
  throw createAbortError3();
294691
294978
  }
294692
- await agent.session.prompt(message, { signal: abortSignal });
294979
+ await promptWithFallback(agent.session, message, { signal: abortSignal });
294693
294980
  if (abortSignal.aborted) {
294694
294981
  throw createAbortError3();
294695
294982
  }
@@ -294720,7 +295007,8 @@ async function continueAgentConversation2(session, message) {
294720
295007
  if (abortSignal.aborted) {
294721
295008
  throw createAbortError3();
294722
295009
  }
294723
- await agent.session.prompt(
295010
+ await promptWithFallback(
295011
+ agent.session,
294724
295012
  'Your previous response could not be parsed as JSON. Please respond with ONLY a valid JSON object: either {"type":"question","data":{...}} or {"type":"complete","data":{"missionTitle":"...","missionDescription":"...","milestones":[...]}}. No markdown, no explanation, just the JSON.',
294725
295013
  { signal: abortSignal }
294726
295014
  );
@@ -295047,7 +295335,16 @@ var init_mission_interview = __esm({
295047
295335
  init_src5();
295048
295336
  init_planning_board_tools();
295049
295337
  MISSION_INTERVIEW_BUILTIN_WEB_TOOLS = ["WebSearch", "WebFetch"];
295050
- createFnAgent6 = createFnAgent2;
295338
+ createFnAgent6 = async (options) => {
295339
+ const { pluginRunner, runtimeHint, settings, ...runtimeOptions } = options ?? {};
295340
+ return createResolvedAgentSession({
295341
+ sessionPurpose: "executor",
295342
+ ...runtimeHint ? { runtimeHint } : {},
295343
+ ...pluginRunner ? { pluginRunner } : {},
295344
+ ...settings ? { settings } : {},
295345
+ ...runtimeOptions
295346
+ });
295347
+ };
295051
295348
  diagnostics4 = createSessionDiagnostics("mission-interview");
295052
295349
  SESSION_TTL_MS3 = 7 * 24 * 60 * 60 * 1e3;
295053
295350
  CLEANUP_INTERVAL_MS4 = 5 * 60 * 1e3;
@@ -295607,6 +295904,8 @@ async function createTargetInterviewAgent(session, rootDir, store, pluginRunner)
295607
295904
  mcpServers,
295608
295905
  ...laneModelOptions(model),
295609
295906
  allowMcpToolsInReadonly: true,
295907
+ // FNXC:MissionInterviewRuntimeResolution 2026-08-16-14:37: forward the plugin runner so the shared seam can route CLI-runtime model selections to their runtime plugins.
295908
+ ...pluginRunner ? { pluginRunner } : {},
295610
295909
  customTools: [...createPlanningBoardTools(store)],
295611
295910
  /*
295612
295911
  FNXC:InterviewSkills 2026-06-17-21:42:
@@ -295719,7 +296018,8 @@ async function ensureInterviewAgent(session, rootDir, store, historyForReplay, p
295719
296018
  if (abortSignal.aborted) {
295720
296019
  throw createAbortError3();
295721
296020
  }
295722
- await session.agent.session.prompt(
296021
+ await promptWithFallback(
296022
+ session.agent.session,
295723
296023
  [
295724
296024
  "Previous conversation summary:",
295725
296025
  historySummary,
@@ -295781,7 +296081,7 @@ async function continueAgentConversation3(session, message) {
295781
296081
  if (abortSignal.aborted) {
295782
296082
  throw createAbortError3();
295783
296083
  }
295784
- await agent.session.prompt(message, { signal: abortSignal });
296084
+ await promptWithFallback(agent.session, message, { signal: abortSignal });
295785
296085
  if (abortSignal.aborted) {
295786
296086
  throw createAbortError3();
295787
296087
  }
@@ -295812,7 +296112,8 @@ async function continueAgentConversation3(session, message) {
295812
296112
  if (abortSignal.aborted) {
295813
296113
  throw createAbortError3();
295814
296114
  }
295815
- await agent.session.prompt(
296115
+ await promptWithFallback(
296116
+ agent.session,
295816
296117
  'Your previous response could not be parsed as JSON. Please respond with ONLY a valid JSON object: either {"type":"question","data":{...}} or {"type":"complete","data":{"title":"...","description":"...","planningNotes":"...","verification":"..."}}. No markdown, no explanation, just the JSON.',
295817
296118
  { signal: abortSignal }
295818
296119
  );
@@ -296135,7 +296436,16 @@ var init_milestone_slice_interview = __esm({
296135
296436
  init_planning_board_tools();
296136
296437
  init_lane_session_model();
296137
296438
  diagnostics5 = createSessionDiagnostics("milestone-slice-interview");
296138
- createFnAgent7 = createFnAgent2;
296439
+ createFnAgent7 = async (options) => {
296440
+ const { pluginRunner, runtimeHint, settings, ...runtimeOptions } = options ?? {};
296441
+ return createResolvedAgentSession({
296442
+ sessionPurpose: "executor",
296443
+ ...runtimeHint ? { runtimeHint } : {},
296444
+ ...pluginRunner ? { pluginRunner } : {},
296445
+ ...settings ? { settings } : {},
296446
+ ...runtimeOptions
296447
+ });
296448
+ };
296139
296449
  SESSION_TTL_MS4 = 7 * 24 * 60 * 60 * 1e3;
296140
296450
  CLEANUP_INTERVAL_MS5 = 5 * 60 * 1e3;
296141
296451
  MAX_SESSIONS_PER_IP_PER_HOUR3 = 5;
@@ -390530,9 +390840,14 @@ var init_register_auth_routes = __esm({
390530
390840
  }
390531
390841
  return await pendingLogin.inputPromise;
390532
390842
  },
390533
- // AuthStorage.login() forwards callbacks to provider-specific OAuth
390534
- // implementations verbatim. openai-codex supports this optional hook
390535
- // to race pasted codes against the localhost callback server.
390843
+ /*
390844
+ FNXC:ProviderAuth 2026-08-18-00:26:
390845
+ `onManualCodeInput` and `onSelect` are dispatched by prompt TYPE in AuthStorage.login()'s
390846
+ pi `AuthInteraction` shim (packages/engine/src/auth/auth-storage.ts), not forwarded
390847
+ verbatim as an older comment here claimed. Both were dead code after login moved to pi's
390848
+ ModelRuntime, which is what broke Codex login: its `select` prompt fell through to
390849
+ `onPrompt` and waited on a paste the UI never asked for.
390850
+ */
390536
390851
  onManualCodeInput: async () => await pendingLogin.inputPromise,
390537
390852
  onProgress: () => {
390538
390853
  },