@runfusion/fusion 0.59.0 → 0.60.0

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 (118) hide show
  1. package/dist/bin.js +173 -16
  2. package/dist/client/.vite/manifest.json +239 -239
  3. package/dist/client/assets/{AgentDetailView-UmilJU0C.js → AgentDetailView-BBjuuYbU.js} +1 -1
  4. package/dist/client/assets/{AgentPermissionPolicyEditor-DqYOX1kN.js → AgentPermissionPolicyEditor-DOdy1ln0.js} +1 -1
  5. package/dist/client/assets/{AgentsView-Dt0nKyx7.js → AgentsView-DlyT08sc.js} +3 -3
  6. package/dist/client/assets/{ChatView-C7trV16u.js → ChatView-CJBnc6rJ.js} +1 -1
  7. package/dist/client/assets/{CommandCenter-Dsg16_mK.js → CommandCenter-BhRLZmOH.js} +1 -1
  8. package/dist/client/assets/{DevServerView-DnpnAU_g.js → DevServerView-DRpi8Xqz.js} +1 -1
  9. package/dist/client/assets/{DirectoryPicker-BzpWdpTC.js → DirectoryPicker-Bw_A-64N.js} +1 -1
  10. package/dist/client/assets/{DocumentsView-C2jRDIo6.js → DocumentsView-w0eDbpbG.js} +1 -1
  11. package/dist/client/assets/{EvalsView-M1nIXx-S.js → EvalsView-DxQALLwD.js} +1 -1
  12. package/dist/client/assets/{ExperimentalAgentOnboardingModal-5Kg2iQtB.js → ExperimentalAgentOnboardingModal-BuEWZrjl.js} +1 -1
  13. package/dist/client/assets/{GoalsView-7bFpy-lr.js → GoalsView-C3MGEtSt.js} +1 -1
  14. package/dist/client/assets/{InsightsView-D0HPy3RP.js → InsightsView-C0-BkE8_.js} +1 -1
  15. package/dist/client/assets/{MemoryView-CNzJcoPi.js → MemoryView-Dd8uiLHH.js} +1 -1
  16. package/dist/client/assets/{PiExtensionsManager-D0a8Q47c.js → PiExtensionsManager-DlsEVOjG.js} +1 -1
  17. package/dist/client/assets/{PluginManager-N2Ne57i_.js → PluginManager-Cf9AOCcC.js} +1 -1
  18. package/dist/client/assets/{PullRequestView-Be4GM2H5.js → PullRequestView-hm77QtHV.js} +1 -1
  19. package/dist/client/assets/{ResearchView-DYW9ViMl.js → ResearchView-BMQEnYH6.js} +1 -1
  20. package/dist/client/assets/{SecretsView-B3jEFeGp.js → SecretsView-Dc3sWf40.js} +1 -1
  21. package/dist/client/assets/{SessionTerminal-DGFADOH4.js → SessionTerminal-CEv1G-9-.js} +1 -1
  22. package/dist/client/assets/SettingsModal-DFrTDsBm.js +21 -0
  23. package/dist/client/assets/{SettingsModal-Lw0RmeRd.js → SettingsModal-TuphE_CP.js} +1 -1
  24. package/dist/client/assets/{SetupWizardModal-BifMmJIa.js → SetupWizardModal-CNGogJJp.js} +2 -2
  25. package/dist/client/assets/{ShadcnColorPicker-B1UClHqm.js → ShadcnColorPicker-1Z7JIWTE.js} +1 -1
  26. package/dist/client/assets/{SkillsView--U-5lH1V.js → SkillsView-CjPvmnz6.js} +1 -1
  27. package/dist/client/assets/{TodoView-BwxNdIXm.js → TodoView-DmJPSWOu.js} +1 -1
  28. package/dist/client/assets/{WorkflowNodeEditor-BmTZR0i8.js → WorkflowNodeEditor-BqO2yRXe.js} +1 -1
  29. package/dist/client/assets/{agentSkills-PqEK0Uf_.js → agentSkills-BNahUMFe.js} +1 -1
  30. package/dist/client/assets/{app-BlgX3hw4.js → app-BzgEwAOr.js} +1 -1
  31. package/dist/client/assets/{architectureDiagram-3BPJPVTR-DxAKryer.js → architectureDiagram-3BPJPVTR-Bb_ZGdtz.js} +1 -1
  32. package/dist/client/assets/{blockDiagram-GPEHLZMM-BfPC7WG4.js → blockDiagram-GPEHLZMM-CWfWJnIM.js} +1 -1
  33. package/dist/client/assets/{c4Diagram-AAUBKEIU-DnVJBAB1.js → c4Diagram-AAUBKEIU-Dufe_2hy.js} +1 -1
  34. package/dist/client/assets/channel-BYHFEnHT.js +1 -0
  35. package/dist/client/assets/{chunk-2J33WTMH-2LaGYtnx.js → chunk-2J33WTMH-BdKWX3Y7.js} +1 -1
  36. package/dist/client/assets/{chunk-4BX2VUAB-C7xxOb1T.js → chunk-4BX2VUAB-CQ9_zgu6.js} +1 -1
  37. package/dist/client/assets/{chunk-55IACEB6-CAxHAFXx.js → chunk-55IACEB6-DEFTCISD.js} +1 -1
  38. package/dist/client/assets/{chunk-727SXJPM-CnZuaU-I.js → chunk-727SXJPM-8RnJp1fx.js} +1 -1
  39. package/dist/client/assets/{chunk-AQP2D5EJ-DutKSMk1.js → chunk-AQP2D5EJ-DJg6awe1.js} +1 -1
  40. package/dist/client/assets/{chunk-FMBD7UC4-C7PQ58jc.js → chunk-FMBD7UC4-Bw-OImRT.js} +1 -1
  41. package/dist/client/assets/{chunk-ND2GUHAM-BQ0UHfJw.js → chunk-ND2GUHAM-BSx9p0RO.js} +1 -1
  42. package/dist/client/assets/{chunk-QZHKN3VN-BadmXu1v.js → chunk-QZHKN3VN-Dbdv72P6.js} +1 -1
  43. package/dist/client/assets/classDiagram-4FO5ZUOK-BLstvJ1W.js +1 -0
  44. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BLstvJ1W.js +1 -0
  45. package/dist/client/assets/{cose-bilkent-S5V4N54A-37z9Hx7d.js → cose-bilkent-S5V4N54A-CXtcC6U2.js} +1 -1
  46. package/dist/client/assets/{dagre-BM42HDAG-B70rt1ZW.js → dagre-BM42HDAG-BO0r4g14.js} +1 -1
  47. package/dist/client/assets/{dashboard-view-GT7dDNd7.js → dashboard-view-BTnVGch5.js} +1 -1
  48. package/dist/client/assets/{dashboard-view-DdAL0vfN.js → dashboard-view-CoDeYJbQ.js} +1 -1
  49. package/dist/client/assets/{diagram-2AECGRRQ-se4pabEk.js → diagram-2AECGRRQ-CLmeU2g6.js} +1 -1
  50. package/dist/client/assets/{diagram-5GNKFQAL-ijyxpVgX.js → diagram-5GNKFQAL-CKyM23Jy.js} +1 -1
  51. package/dist/client/assets/{diagram-KO2AKTUF-DUGQ8jXI.js → diagram-KO2AKTUF-ByeVRDs_.js} +1 -1
  52. package/dist/client/assets/{diagram-LMA3HP47-BYydC37K.js → diagram-LMA3HP47-r8qKTJDn.js} +1 -1
  53. package/dist/client/assets/{diagram-OG6HWLK6-DlUn5jkD.js → diagram-OG6HWLK6-D2ugPdm7.js} +1 -1
  54. package/dist/client/assets/{erDiagram-TEJ5UH35-ChYKGDIc.js → erDiagram-TEJ5UH35-dLzbDn0G.js} +1 -1
  55. package/dist/client/assets/{flowDiagram-I6XJVG4X-CoQKr6ba.js → flowDiagram-I6XJVG4X-et7EENd6.js} +1 -1
  56. package/dist/client/assets/{folder-open-YuIEuDwd.js → folder-open-BVtcjVIK.js} +1 -1
  57. package/dist/client/assets/{ganttDiagram-6RSMTGT7-Cff6URun.js → ganttDiagram-6RSMTGT7-DmiabChP.js} +1 -1
  58. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CnlZVE6T.js → gitGraphDiagram-PVQCEYII-I1vbhqer.js} +1 -1
  59. package/dist/client/assets/index-inWk2g6R.js +2540 -0
  60. package/dist/client/assets/{infoDiagram-5YYISTIA-DYLBAKrj.js → infoDiagram-5YYISTIA-xd6L9Gq3.js} +1 -1
  61. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-7xSxQNhn.js → ishikawaDiagram-YF4QCWOH-fUeEYBvD.js} +1 -1
  62. package/dist/client/assets/{journeyDiagram-JHISSGLW-DREqJGeQ.js → journeyDiagram-JHISSGLW-B7xjU8Oh.js} +1 -1
  63. package/dist/client/assets/{kanban-definition-UN3LZRKU-_lzeYhpL.js → kanban-definition-UN3LZRKU-CJ8oRjFI.js} +1 -1
  64. package/dist/client/assets/{mermaid.core-DNTJMy0V.js → mermaid.core-2udKsaH3.js} +4 -4
  65. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DR9UulDp.js → mindmap-definition-RKZ34NQL-CVywzN7Q.js} +1 -1
  66. package/dist/client/assets/{pieDiagram-4H26LBE5-DD1LCdSp.js → pieDiagram-4H26LBE5-8vzzC4Mg.js} +1 -1
  67. package/dist/client/assets/{puzzle-DaVSYDOd.js → puzzle-D60d3Nv1.js} +1 -1
  68. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-iLEGylFT.js → quadrantDiagram-W4KKPZXB-Cxyb4Mom.js} +1 -1
  69. package/dist/client/assets/{requirementDiagram-4Y6WPE33-D7IX9UbY.js → requirementDiagram-4Y6WPE33-Bs5RaG7r.js} +1 -1
  70. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DC30taEV.js → sankeyDiagram-5OEKKPKP-Jf7Zq43D.js} +1 -1
  71. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DjMKbjmL.js → sequenceDiagram-3UESZ5HK-CG0I780H.js} +1 -1
  72. package/dist/client/assets/{shield-alert-BcyPZs5t.js → shield-alert-B7JyuWPR.js} +1 -1
  73. package/dist/client/assets/{stateDiagram-AJRCARHV-DJSnSkUL.js → stateDiagram-AJRCARHV-C1c5XtKG.js} +1 -1
  74. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-KC2rSU3J.js → stateDiagram-v2-BHNVJYJU-Cv7_pOt_.js} +1 -1
  75. package/dist/client/assets/{timeline-definition-PNZ67QCA-5DyrH8WZ.js → timeline-definition-PNZ67QCA-BWg-lsI0.js} +1 -1
  76. package/dist/client/assets/{upload-C_8IHSzk.js → upload-Dxv5FPaS.js} +1 -1
  77. package/dist/client/assets/{users-DfGiwmqG.js → users-DvKg3opr.js} +1 -1
  78. package/dist/client/assets/{vennDiagram-CIIHVFJN-Bh5X-uVf.js → vennDiagram-CIIHVFJN-gFjFmLlv.js} +1 -1
  79. package/dist/client/assets/{wardley-L42UT6IY-ZIwV-wIZ.js → wardley-L42UT6IY-BaCNX8ou.js} +1 -1
  80. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DI92L1jA.js → wardleyDiagram-YWT4CUSO-BRR6aw0q.js} +1 -1
  81. package/dist/client/assets/{xychartDiagram-2RQKCTM6-B6RjJCM8.js → xychartDiagram-2RQKCTM6-D6Gwn1XW.js} +1 -1
  82. package/dist/client/index.html +1 -1
  83. package/dist/client/version.json +1 -1
  84. package/dist/droid-cli/package.json +1 -1
  85. package/dist/extension.js +173 -16
  86. package/dist/pi-claude-cli/package.json +1 -1
  87. package/dist/plugin-sdk/index.d.ts +7 -0
  88. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +0 -6
  89. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  90. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  91. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +0 -5
  92. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  93. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +0 -5
  94. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  95. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +0 -5
  96. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  97. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +0 -5
  98. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  99. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +0 -6
  100. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  101. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +0 -5
  102. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  103. package/dist/plugins/fusion-plugin-linear-import/bundled.js +0 -5
  104. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  105. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +0 -5
  106. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  107. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +0 -5
  108. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  109. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  110. package/dist/plugins/fusion-plugin-roadmap/bundled.js +0 -5
  111. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  112. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  113. package/package.json +1 -1
  114. package/dist/client/assets/SettingsModal-CtOCCZEj.js +0 -21
  115. package/dist/client/assets/channel-D23u9xEh.js +0 -1
  116. package/dist/client/assets/classDiagram-4FO5ZUOK-BMIDIijD.js +0 -1
  117. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BMIDIijD.js +0 -1
  118. package/dist/client/assets/index-aBQwNV_I.js +0 -2540
package/dist/bin.js CHANGED
@@ -1219,6 +1219,12 @@ var init_settings_schema = __esm({
1219
1219
  titleSummarizerGlobalProvider: void 0,
1220
1220
  titleSummarizerGlobalModelId: void 0,
1221
1221
  /*
1222
+ FNXC:Settings-MergerModel 2026-07-13-07:52:
1223
+ Global merger baseline lane (provider/model/thinking) is independent of executor/planner/reviewer so operators can pin a merge-capable model under Settings → Global Models without changing other lanes. Undefined falls through to defaultProvider/defaultModelId at resolve time.
1224
+ */
1225
+ mergerGlobalProvider: void 0,
1226
+ mergerGlobalModelId: void 0,
1227
+ /*
1222
1228
  FNXC:Settings-ThinkingLevel 2026-07-10-00:00:
1223
1229
  Global model lanes can override the default thinking effort independently. Undefined preserves the existing inheritance to `defaultThinkingLevel`.
1224
1230
  */
@@ -1226,6 +1232,7 @@ var init_settings_schema = __esm({
1226
1232
  planningGlobalThinkingLevel: void 0,
1227
1233
  validatorGlobalThinkingLevel: void 0,
1228
1234
  titleSummarizerGlobalThinkingLevel: void 0,
1235
+ mergerGlobalThinkingLevel: void 0,
1229
1236
  // Daemon mode settings
1230
1237
  daemonToken: void 0,
1231
1238
  daemonPort: 4040,
@@ -1416,6 +1423,11 @@ var init_settings_schema = __esm({
1416
1423
  */
1417
1424
  openMobileTasksInPopup: false,
1418
1425
  /*
1426
+ FNXC:TaskPopupViewGating 2026-07-13-00:00:
1427
+ Default off preserves current always-visible task-detail popup behavior. When true, the dashboard render gate shows each open task-detail FloatingWindow only on the Board/List view where it was opened without clearing popup snapshots or their shared persisted geometry.
1428
+ */
1429
+ taskPopupsBoardListOnly: false,
1430
+ /*
1419
1431
  FNXC:TaskCardCostBadge 2026-07-11-12:15:
1420
1432
  Default off preserves existing board-card density. When true, the dashboard may render a read-time derived cost badge only for tasks with positive token usage; unavailable pricing remains the guess-free “—” sentinel.
1421
1433
  */
@@ -1617,6 +1629,13 @@ var init_settings_schema = __esm({
1617
1629
  titleSummarizerFallbackProvider: void 0,
1618
1630
  titleSummarizerFallbackModelId: void 0,
1619
1631
  titleSummarizerFallbackThinkingLevel: void 0,
1632
+ /*
1633
+ FNXC:Settings-MergerModel 2026-07-13-07:52:
1634
+ Merger model lane stays project-scoped (not workflow-moved) like title summarizer: Settings → Project Models can override the global merger baseline without binding the choice to a workflow graph.
1635
+ */
1636
+ mergerProvider: void 0,
1637
+ mergerModelId: void 0,
1638
+ mergerThinkingLevel: void 0,
1620
1639
  prTitlePromptInstructions: void 0,
1621
1640
  prDescriptionPromptInstructions: void 0,
1622
1641
  scripts: void 0,
@@ -2666,6 +2685,22 @@ function resolveTitleSummarizerSettingsModel(settings) {
2666
2685
  settings
2667
2686
  );
2668
2687
  }
2688
+ function resolveMergerSettingsModel(settings) {
2689
+ return applyTestModeOverrides(
2690
+ pickFirstModelPair(
2691
+ {
2692
+ provider: settings?.mergerProvider,
2693
+ modelId: settings?.mergerModelId
2694
+ },
2695
+ {
2696
+ provider: settings?.mergerGlobalProvider,
2697
+ modelId: settings?.mergerGlobalModelId
2698
+ },
2699
+ resolveProjectDefaultModel(settings)
2700
+ ),
2701
+ settings
2702
+ );
2703
+ }
2669
2704
  function resolveTaskExecutionModel(task, settings) {
2670
2705
  return applyTestModeOverrides(
2671
2706
  pickFirstModelPair(
@@ -93683,6 +93718,7 @@ __export(src_exports, {
93683
93718
  resolveMaxReworkCycles: () => resolveMaxReworkCycles,
93684
93719
  resolveMemoryBackend: () => resolveMemoryBackend,
93685
93720
  resolveMemoryInstructionContext: () => resolveMemoryInstructionContext,
93721
+ resolveMergerSettingsModel: () => resolveMergerSettingsModel,
93686
93722
  resolveOptionalReviewRevisionBudget: () => resolveOptionalReviewRevisionBudget,
93687
93723
  resolveOptionalStepRevisionBudget: () => resolveOptionalStepRevisionBudget,
93688
93724
  resolvePersistAgentThinkingLog: () => resolvePersistAgentThinkingLog,
@@ -140730,7 +140766,12 @@ function resolveTitleSummarizerThinkingLevel(settings) {
140730
140766
  );
140731
140767
  }
140732
140768
  function resolveMergerThinkingLevel(settings) {
140733
- return firstThinkingLevel2(settings?.defaultThinkingLevelOverride, settings?.defaultThinkingLevel);
140769
+ return firstThinkingLevel2(
140770
+ settings?.mergerThinkingLevel,
140771
+ settings?.mergerGlobalThinkingLevel,
140772
+ settings?.defaultThinkingLevelOverride,
140773
+ settings?.defaultThinkingLevel
140774
+ );
140734
140775
  }
140735
140776
  function resolveExecutorFallbackThinkingLevel(taskThinkingLevel, settings) {
140736
140777
  return firstThinkingLevel2(
@@ -140910,8 +140951,8 @@ function resolveMergerSessionModel(settings, assignedAgentRuntimeConfig) {
140910
140951
  modelId: TEST_MODE_RESOLVED.modelId
140911
140952
  };
140912
140953
  }
140913
- const defaultModel = resolveProjectDefaultModel(settings);
140914
- return pickSettingsThenRuntimeModel(defaultModel, assignedAgentRuntimeConfig);
140954
+ const mergerModel = resolveMergerSettingsModel(settings);
140955
+ return pickSettingsThenRuntimeModel(mergerModel, assignedAgentRuntimeConfig);
140915
140956
  }
140916
140957
  async function createResolvedAgentSession(options) {
140917
140958
  const { sessionPurpose, pluginRunner, runtimeHint, runAuditor, settings, ...runtimeOptionsRaw } = options;
@@ -152028,7 +152069,9 @@ function readHeartbeatTimerRepairMetadata(agent) {
152028
152069
  return {
152029
152070
  repairedAt: typeof candidate.repairedAt === "string" ? candidate.repairedAt : void 0,
152030
152071
  staleAtRepair: typeof candidate.staleAtRepair === "boolean" ? candidate.staleAtRepair : void 0,
152031
- staleRepairReason: typeof candidate.staleRepairReason === "string" ? candidate.staleRepairReason : void 0
152072
+ staleRepairReason: typeof candidate.staleRepairReason === "string" ? candidate.staleRepairReason : void 0,
152073
+ consecutiveNonAdvancingRearms: typeof candidate.consecutiveNonAdvancingRearms === "number" ? candidate.consecutiveNonAdvancingRearms : void 0,
152074
+ nonAdvancingEscalated: typeof candidate.nonAdvancingEscalated === "boolean" ? candidate.nonAdvancingEscalated : void 0
152032
152075
  };
152033
152076
  }
152034
152077
  var MAX_HEARTBEAT_WORKTREE_ACQUISITION_RETRIES, MAX_HEARTBEAT_ERROR_RECOVERY_ATTEMPTS, HEARTBEAT_ERROR_RECOVERY_METADATA_KEY, HEARTBEAT_ERROR_RETRY_EXHAUSTED_PAUSE_REASON, HEARTBEAT_ERROR_UNRECOVERABLE_PAUSE_REASON, promptSizeLog, REPORTS_STALE_INTERVAL_MULTIPLIER, MIN_HEARTBEAT_STALENESS_MS, agentSoulWordsCache, HEARTBEAT_SYSTEM_PROMPT, HEARTBEAT_NO_TASK_SYSTEM_PROMPT, HEARTBEAT_PROCEDURE_STRICT, HEARTBEAT_PROCEDURE_LITE, HEARTBEAT_PROCEDURE_OFF, HEARTBEAT_PROCEDURE, HEARTBEAT_NO_TASK_PROCEDURE_STRICT, HEARTBEAT_NO_TASK_PROCEDURE_LITE, HEARTBEAT_NO_TASK_PROCEDURE_OFF, heartbeatDoneParams, HeartbeatMonitor, OVERDUE_FIRE_JITTER_MS, HeartbeatTriggerScheduler;
@@ -154990,7 +155033,13 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
154990
155033
  * Absent (legacy/no executor wiring) → treated as never effectively executing. */
154991
155034
  isAgentEffectivelyExecuting;
154992
155035
  timerAuditIntervalHandle = null;
155036
+ timerAuditWatchdogHandle = null;
155037
+ lastAuditRanAtMs = 0;
155038
+ nonAdvancingRearmState = /* @__PURE__ */ new Map();
154993
155039
  static TIMER_AUDIT_INTERVAL_MS = 6e4;
155040
+ static TIMER_AUDIT_WATCHDOG_INTERVAL_MS = 6e4;
155041
+ static TIMER_AUDIT_WATCHDOG_STALE_MS = _HeartbeatTriggerScheduler.TIMER_AUDIT_INTERVAL_MS * 3;
155042
+ static NON_ADVANCING_REARM_ESCALATION_THRESHOLD = 3;
154994
155043
  static DEFAULT_REPAIR_STALE_MULTIPLIER = 2;
154995
155044
  static DEFAULT_HEARTBEAT_TIMEOUT_MS = 6e4;
154996
155045
  constructor(store, callback, taskStore, options) {
@@ -155007,13 +155056,52 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155007
155056
  start() {
155008
155057
  if (this.running) return;
155009
155058
  this.running = true;
155059
+ this.lastAuditRanAtMs = Date.now();
155010
155060
  this.watchAssignments();
155011
155061
  this.watchAgentLifecycle();
155012
155062
  void this.auditTimerRegistrations("start");
155063
+ this.armTimerAuditInterval();
155064
+ this.armTimerAuditWatchdog();
155065
+ heartbeatLog.log("HeartbeatTriggerScheduler started");
155066
+ }
155067
+ armTimerAuditInterval() {
155068
+ if (this.timerAuditIntervalHandle) {
155069
+ clearInterval(this.timerAuditIntervalHandle);
155070
+ this.timerAuditIntervalHandle = null;
155071
+ }
155072
+ if (!this.running) {
155073
+ return;
155074
+ }
155013
155075
  this.timerAuditIntervalHandle = setInterval(() => {
155014
155076
  void this.auditTimerRegistrations("interval");
155015
155077
  }, _HeartbeatTriggerScheduler.TIMER_AUDIT_INTERVAL_MS);
155016
- heartbeatLog.log("HeartbeatTriggerScheduler started");
155078
+ }
155079
+ armTimerAuditWatchdog() {
155080
+ if (this.timerAuditWatchdogHandle) {
155081
+ clearInterval(this.timerAuditWatchdogHandle);
155082
+ this.timerAuditWatchdogHandle = null;
155083
+ }
155084
+ if (!this.running) {
155085
+ return;
155086
+ }
155087
+ this.timerAuditWatchdogHandle = setInterval(() => {
155088
+ void this.checkTimerAuditLiveness();
155089
+ }, _HeartbeatTriggerScheduler.TIMER_AUDIT_WATCHDOG_INTERVAL_MS);
155090
+ }
155091
+ async checkTimerAuditLiveness() {
155092
+ if (!this.running) {
155093
+ return;
155094
+ }
155095
+ const now = Date.now();
155096
+ const elapsedMs = this.lastAuditRanAtMs > 0 ? now - this.lastAuditRanAtMs : Number.POSITIVE_INFINITY;
155097
+ if (elapsedMs <= _HeartbeatTriggerScheduler.TIMER_AUDIT_WATCHDOG_STALE_MS) {
155098
+ return;
155099
+ }
155100
+ heartbeatLog.warn(
155101
+ `Heartbeat timer audit watchdog re-armed stalled auditor reason=heartbeat-audit-watchdog-rearmed elapsedMs=${elapsedMs} thresholdMs=${_HeartbeatTriggerScheduler.TIMER_AUDIT_WATCHDOG_STALE_MS}`
155102
+ );
155103
+ this.armTimerAuditInterval();
155104
+ await this.auditTimerRegistrations("interval");
155017
155105
  }
155018
155106
  /**
155019
155107
  * Stop the scheduler and clear all timers.
@@ -155036,6 +155124,12 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155036
155124
  clearInterval(this.timerAuditIntervalHandle);
155037
155125
  this.timerAuditIntervalHandle = null;
155038
155126
  }
155127
+ if (this.timerAuditWatchdogHandle) {
155128
+ clearInterval(this.timerAuditWatchdogHandle);
155129
+ this.timerAuditWatchdogHandle = null;
155130
+ }
155131
+ this.lastAuditRanAtMs = 0;
155132
+ this.nonAdvancingRearmState.clear();
155039
155133
  heartbeatLog.log("HeartbeatTriggerScheduler stopped");
155040
155134
  }
155041
155135
  /**
@@ -155180,6 +155274,7 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155180
155274
  unregisterAgent(agentId) {
155181
155275
  this.registrationEpochs.set(agentId, (this.registrationEpochs.get(agentId) ?? 0) + 1);
155182
155276
  this.pendingAssignments.delete(agentId);
155277
+ this.nonAdvancingRearmState.delete(agentId);
155183
155278
  if (this.timers.has(agentId)) {
155184
155279
  this.clearAgentTimer(agentId);
155185
155280
  heartbeatLog.log(`Unregistered timer for ${agentId}`);
@@ -155501,7 +155596,7 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155501
155596
  );
155502
155597
  return { reaped: true, elapsedMs, thresholdMs };
155503
155598
  }
155504
- async markRepairMetadata(agent, staleAtRepair, staleRepairReason) {
155599
+ async markRepairMetadata(agent, staleAtRepair, staleRepairReason, options) {
155505
155600
  const updater = this.store.updateAgent;
155506
155601
  if (typeof updater !== "function") {
155507
155602
  return;
@@ -155511,9 +155606,11 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155511
155606
  const nextRepair = {
155512
155607
  repairedAt,
155513
155608
  staleAtRepair,
155514
- ...staleAtRepair && staleRepairReason ? { staleRepairReason } : {}
155609
+ ...staleAtRepair && staleRepairReason ? { staleRepairReason } : {},
155610
+ ...typeof options?.consecutiveNonAdvancingRearms === "number" ? { consecutiveNonAdvancingRearms: options.consecutiveNonAdvancingRearms } : {},
155611
+ ...options?.nonAdvancingEscalated ? { nonAdvancingEscalated: true } : {}
155515
155612
  };
155516
- const didChange = existing.repairedAt !== nextRepair.repairedAt || existing.staleAtRepair !== nextRepair.staleAtRepair || existing.staleRepairReason !== nextRepair.staleRepairReason;
155613
+ const didChange = existing.repairedAt !== nextRepair.repairedAt || existing.staleAtRepair !== nextRepair.staleAtRepair || existing.staleRepairReason !== nextRepair.staleRepairReason || existing.consecutiveNonAdvancingRearms !== nextRepair.consecutiveNonAdvancingRearms || existing.nonAdvancingEscalated !== nextRepair.nonAdvancingEscalated;
155517
155614
  if (!didChange) {
155518
155615
  return;
155519
155616
  }
@@ -155523,6 +155620,7 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155523
155620
  }
155524
155621
  async auditTimerRegistrations(reason = "interval") {
155525
155622
  if (!this.running) return;
155623
+ this.lastAuditRanAtMs = Date.now();
155526
155624
  try {
155527
155625
  const settings = this.taskStore && typeof this.taskStore.getSettings === "function" ? await this.taskStore.getSettings() : null;
155528
155626
  const staleMultiplier = this.resolveRepairStaleMultiplier(settings);
@@ -155532,6 +155630,7 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155532
155630
  let zombieRearmedCount = 0;
155533
155631
  for (const agent of agents) {
155534
155632
  if (!this.isTimerEligibleAgent(agent)) {
155633
+ this.nonAdvancingRearmState.delete(agent.id);
155535
155634
  if (this.timers.has(agent.id)) {
155536
155635
  this.unregisterAgent(agent.id);
155537
155636
  heartbeatLog.log(`Timer audit cleared orphaned timer for non-eligible agent ${agent.id} (audit:${reason})`);
@@ -155542,7 +155641,10 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155542
155641
  const staleThresholdMs = this.getRepairStaleThresholdMs(agent, staleMultiplier);
155543
155642
  const elapsedMs = getHeartbeatAgeMs(agent);
155544
155643
  const staleAtRepair = Number.isFinite(elapsedMs) && elapsedMs > staleThresholdMs;
155545
- if (hasTimerEntry && !staleAtRepair) continue;
155644
+ if (hasTimerEntry && !staleAtRepair) {
155645
+ this.nonAdvancingRearmState.delete(agent.id);
155646
+ continue;
155647
+ }
155546
155648
  const isZombieRearm = hasTimerEntry && staleAtRepair;
155547
155649
  const activeRun = await this.store.getActiveHeartbeatRun(agent.id);
155548
155650
  const activeRunId = activeRun?.id ?? null;
@@ -155551,6 +155653,7 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155551
155653
  let activeRunThresholdMs = Number.NaN;
155552
155654
  if (activeRun) {
155553
155655
  if (settings?.globalPause || settings?.enginePaused) {
155656
+ this.nonAdvancingRearmState.delete(agent.id);
155554
155657
  heartbeatLog.log(`Timer audit skipped re-arm for ${agent.id} (active run)`);
155555
155658
  continue;
155556
155659
  }
@@ -155559,15 +155662,34 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155559
155662
  activeRunElapsedMs = reapResult.elapsedMs;
155560
155663
  activeRunThresholdMs = reapResult.thresholdMs;
155561
155664
  if (!reapedActiveRun) {
155665
+ this.nonAdvancingRearmState.delete(agent.id);
155562
155666
  heartbeatLog.log(`Timer audit skipped re-arm for ${agent.id} (active run)`);
155563
155667
  continue;
155564
155668
  }
155565
155669
  }
155670
+ let consecutiveNonAdvancingRearms;
155671
+ let nonAdvancingEscalated = false;
155672
+ let escalationReason;
155673
+ if (isZombieRearm && !settings?.globalPause && !settings?.enginePaused) {
155674
+ const heartbeatMarker = typeof agent.lastHeartbeatAt === "string" ? agent.lastHeartbeatAt : null;
155675
+ const previous = this.nonAdvancingRearmState.get(agent.id);
155676
+ consecutiveNonAdvancingRearms = previous && previous.lastHeartbeatAt === heartbeatMarker ? previous.count + 1 : 1;
155677
+ this.nonAdvancingRearmState.set(agent.id, { lastHeartbeatAt: heartbeatMarker, count: consecutiveNonAdvancingRearms });
155678
+ nonAdvancingEscalated = consecutiveNonAdvancingRearms >= _HeartbeatTriggerScheduler.NON_ADVANCING_REARM_ESCALATION_THRESHOLD;
155679
+ if (nonAdvancingEscalated) {
155680
+ escalationReason = `heartbeat-rearm-nonadvancing-escalated: ${consecutiveNonAdvancingRearms} consecutive zombie re-arms without lastHeartbeatAt advancing`;
155681
+ }
155682
+ } else {
155683
+ this.nonAdvancingRearmState.delete(agent.id);
155684
+ }
155566
155685
  this.registerAgent(agent.id, this.getAgentTimerConfig(agent), {
155567
155686
  lastHeartbeatAt: agent.lastHeartbeatAt
155568
155687
  });
155569
- const staleRepairReason = staleAtRepair ? isZombieRearm ? `zombie-timer-rearmed: no heartbeat for ${Math.round(elapsedMs / 1e3)}s while a timer entry remained present (threshold ${Math.round(staleThresholdMs / 1e3)}s)` : `No heartbeat for ${Math.round(elapsedMs / 1e3)}s before timer audit repair (threshold ${Math.round(staleThresholdMs / 1e3)}s)` : void 0;
155570
- await this.markRepairMetadata(agent, staleAtRepair, staleRepairReason);
155688
+ const staleRepairReason = staleAtRepair ? escalationReason ? `${escalationReason}; zombie-timer-rearmed: no heartbeat for ${Math.round(elapsedMs / 1e3)}s while a timer entry remained present (threshold ${Math.round(staleThresholdMs / 1e3)}s)` : isZombieRearm ? `zombie-timer-rearmed: no heartbeat for ${Math.round(elapsedMs / 1e3)}s while a timer entry remained present (threshold ${Math.round(staleThresholdMs / 1e3)}s)` : `No heartbeat for ${Math.round(elapsedMs / 1e3)}s before timer audit repair (threshold ${Math.round(staleThresholdMs / 1e3)}s)` : void 0;
155689
+ await this.markRepairMetadata(agent, staleAtRepair, staleRepairReason, {
155690
+ consecutiveNonAdvancingRearms,
155691
+ nonAdvancingEscalated
155692
+ });
155571
155693
  rearmedCount++;
155572
155694
  if (isZombieRearm) zombieRearmedCount++;
155573
155695
  if (reapedActiveRun && activeRunId) {
@@ -155575,7 +155697,11 @@ ${trimPromptMd(taskDetail.prompt, promptTemplate)}` : "No PROMPT.md available.",
155575
155697
  `Timer audit re-armed after stale-run reap reason=timer-audit-rearmed agentId=${agent.id} runId=${activeRunId} elapsedMs=${activeRunElapsedMs} thresholdMs=${activeRunThresholdMs}`
155576
155698
  );
155577
155699
  }
155578
- if (isZombieRearm) {
155700
+ if (nonAdvancingEscalated) {
155701
+ heartbeatLog.warn(
155702
+ `Timer audit escalated non-advancing zombie re-arm reason=heartbeat-rearm-nonadvancing-escalated agentId=${agent.id} count=${consecutiveNonAdvancingRearms} threshold=${_HeartbeatTriggerScheduler.NON_ADVANCING_REARM_ESCALATION_THRESHOLD} (audit:${reason}): ${staleRepairReason}`
155703
+ );
155704
+ } else if (isZombieRearm) {
155579
155705
  heartbeatLog.warn(`Timer audit force re-armed non-advancing agent ${agent.id} reason=zombie-timer-rearmed (audit:${reason}): ${staleRepairReason}`);
155580
155706
  } else if (staleAtRepair) {
155581
155707
  heartbeatLog.warn(`Timer re-armed stale agent ${agent.id} (audit:${reason}): ${staleRepairReason ?? "heartbeat exceeded stale threshold before repair"}`);
@@ -191099,12 +191225,43 @@ function canonicalizePath2(path11) {
191099
191225
  return resolvePath(path11);
191100
191226
  }
191101
191227
  }
191228
+ function countExecuteRequeueTerminalSteps(live) {
191229
+ return live.steps?.filter((step) => step.status === "done" || step.status === "skipped").length ?? 0;
191230
+ }
191231
+ function parseExecuteRequeueLoopProgressSignature(signature) {
191232
+ if (!signature) return null;
191233
+ try {
191234
+ const parsed = JSON.parse(signature);
191235
+ if (typeof parsed.terminalStepCount !== "number" || typeof parsed.totalSteps !== "number") return null;
191236
+ return {
191237
+ terminalStepCount: parsed.terminalStepCount,
191238
+ totalSteps: parsed.totalSteps
191239
+ };
191240
+ } catch {
191241
+ return null;
191242
+ }
191243
+ }
191102
191244
  function buildExecuteRequeueLoopSignature(live) {
191103
191245
  return JSON.stringify({
191104
- currentStep: live.currentStep ?? null,
191105
- steps: live.steps?.map((step) => step.status) ?? []
191246
+ terminalStepCount: countExecuteRequeueTerminalSteps(live),
191247
+ totalSteps: live.steps?.length ?? 0
191106
191248
  });
191107
191249
  }
191250
+ function buildExecuteRequeueLoopHighWaterSignature(live, previousSignature) {
191251
+ const current = parseExecuteRequeueLoopProgressSignature(buildExecuteRequeueLoopSignature(live));
191252
+ const currentTerminalStepCount = current?.terminalStepCount ?? countExecuteRequeueTerminalSteps(live);
191253
+ const totalSteps = current?.totalSteps ?? (live.steps?.length ?? 0);
191254
+ const previous = parseExecuteRequeueLoopProgressSignature(previousSignature);
191255
+ const previousTerminalStepCount = previous?.terminalStepCount ?? currentTerminalStepCount;
191256
+ const madeForwardProgress = previous != null && currentTerminalStepCount > previousTerminalStepCount;
191257
+ return {
191258
+ madeForwardProgress,
191259
+ signature: JSON.stringify({
191260
+ terminalStepCount: Math.max(previousTerminalStepCount, currentTerminalStepCount),
191261
+ totalSteps
191262
+ })
191263
+ };
191264
+ }
191108
191265
  function isTransientMissingTaskJsonError(error48, task) {
191109
191266
  if (error48 instanceof TaskDeletedError) {
191110
191267
  return false;
@@ -197672,8 +197829,8 @@ Graph value: ${failureValue}` : ""}`, budget.key),
197672
197829
  await this.persistTokenUsage(task.id);
197673
197830
  return;
197674
197831
  }
197675
- const signature = buildExecuteRequeueLoopSignature(live);
197676
- const nextCount = live.executeRequeueLoopSignature === signature ? (live.executeRequeueLoopCount ?? 0) + 1 : 1;
197832
+ const { signature, madeForwardProgress } = buildExecuteRequeueLoopHighWaterSignature(live, live.executeRequeueLoopSignature);
197833
+ const nextCount = madeForwardProgress || live.executeRequeueLoopSignature == null ? 1 : (live.executeRequeueLoopCount ?? 0) + 1;
197677
197834
  if (live.executeRequeueLoopCount !== nextCount || live.executeRequeueLoopSignature !== signature) {
197678
197835
  await this.store.updateTask(task.id, {
197679
197836
  executeRequeueLoopCount: nextCount,