@adhdev/daemon-core 0.9.82-rc.49 → 0.9.82-rc.490

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 (473) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +9 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/build-info.d.ts +37 -0
  4. package/dist/chat/source-machine.d.ts +166 -0
  5. package/dist/chat/source-resolver.d.ts +104 -0
  6. package/dist/chat/subscription-updates.d.ts +1 -0
  7. package/dist/cli-adapter-types.d.ts +68 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +220 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
  14. package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
  15. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  16. package/dist/cli-adapters/resolve-executable.d.ts +69 -0
  17. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  18. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  19. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  20. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  21. package/dist/commands/chat-commands-read.d.ts +23 -0
  22. package/dist/commands/chat-commands-scope.d.ts +39 -0
  23. package/dist/commands/chat-commands-shared.d.ts +33 -0
  24. package/dist/commands/chat-commands-write.d.ts +14 -0
  25. package/dist/commands/chat-commands.d.ts +10 -23
  26. package/dist/commands/cli-manager.d.ts +71 -1
  27. package/dist/commands/handler.d.ts +125 -0
  28. package/dist/commands/high-family/index.d.ts +3 -0
  29. package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
  30. package/dist/commands/high-family/mesh-events.d.ts +2 -0
  31. package/dist/commands/high-family/mesh-status.d.ts +2 -0
  32. package/dist/commands/high-family/types.d.ts +64 -0
  33. package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
  34. package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
  35. package/dist/commands/low-family/diagnostics.d.ts +2 -0
  36. package/dist/commands/low-family/index.d.ts +3 -0
  37. package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
  38. package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
  39. package/dist/commands/low-family/notification.d.ts +2 -0
  40. package/dist/commands/low-family/refine-config.d.ts +2 -0
  41. package/dist/commands/low-family/session-host.d.ts +2 -0
  42. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  43. package/dist/commands/low-family/status-meta.d.ts +2 -0
  44. package/dist/commands/low-family/types.d.ts +33 -0
  45. package/dist/commands/med-family/cli-agent.d.ts +2 -0
  46. package/dist/commands/med-family/fast-forward.d.ts +2 -0
  47. package/dist/commands/med-family/ide.d.ts +10 -0
  48. package/dist/commands/med-family/index.d.ts +3 -0
  49. package/dist/commands/med-family/mesh-crud.d.ts +48 -0
  50. package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
  51. package/dist/commands/med-family/mesh-queue.d.ts +2 -0
  52. package/dist/commands/med-family/mesh-restart.d.ts +2 -0
  53. package/dist/commands/med-family/types.d.ts +152 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router-aggregate-status.d.ts +24 -0
  56. package/dist/commands/router-mesh-session-owner.d.ts +59 -0
  57. package/dist/commands/router-refine.d.ts +151 -0
  58. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  59. package/dist/commands/router.d.ts +203 -15
  60. package/dist/commands/upgrade-helper.d.ts +41 -1
  61. package/dist/config/chat-history.d.ts +11 -0
  62. package/dist/config/config.d.ts +19 -0
  63. package/dist/config/mesh-config.d.ts +65 -0
  64. package/dist/config/mesh-json-config.d.ts +199 -0
  65. package/dist/config/registry-resolver.d.ts +54 -0
  66. package/dist/config/repo-settings.d.ts +77 -0
  67. package/dist/config/state-store.d.ts +30 -0
  68. package/dist/daemon/dev-server.d.ts +0 -2
  69. package/dist/detection/cli-detector.d.ts +17 -0
  70. package/dist/detection/ide-detector.d.ts +13 -0
  71. package/dist/detection/win32-ide-version.d.ts +37 -0
  72. package/dist/git/change-impact-config.d.ts +159 -0
  73. package/dist/git/git-commands.d.ts +26 -2
  74. package/dist/git/git-diff.d.ts +6 -0
  75. package/dist/git/git-executor.d.ts +11 -0
  76. package/dist/git/git-status.d.ts +80 -0
  77. package/dist/git/git-types.d.ts +2 -50
  78. package/dist/git/git-worktree.d.ts +71 -1
  79. package/dist/git/index.d.ts +3 -1
  80. package/dist/index.d.ts +70 -17
  81. package/dist/index.js +53532 -19073
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +53283 -18989
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/installer.d.ts +1 -4
  86. package/dist/ipc/local-ipc-server.d.ts +91 -0
  87. package/dist/launch.d.ts +1 -1
  88. package/dist/logging/async-batch-writer.d.ts +10 -0
  89. package/dist/logging/debug-config.d.ts +16 -0
  90. package/dist/logging/log-redactor.d.ts +24 -0
  91. package/dist/logging/log-tail-reader.d.ts +81 -0
  92. package/dist/logging/logger.d.ts +1 -1
  93. package/dist/mesh/contracts.d.ts +256 -0
  94. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  95. package/dist/mesh/coordinator-registry.d.ts +59 -0
  96. package/dist/mesh/mesh-active-work.d.ts +203 -0
  97. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  98. package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
  99. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  100. package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
  101. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  102. package/dist/mesh/mesh-event-forwarding.d.ts +58 -0
  103. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  104. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  105. package/dist/mesh/mesh-events-pending.d.ts +258 -0
  106. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  107. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  108. package/dist/mesh/mesh-events.d.ts +6 -49
  109. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  110. package/dist/mesh/mesh-host-ownership.d.ts +21 -1
  111. package/dist/mesh/mesh-init.d.ts +128 -0
  112. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  113. package/dist/mesh/mesh-ledger.d.ts +139 -1
  114. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  115. package/dist/mesh/mesh-missions.d.ts +281 -0
  116. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  117. package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
  118. package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
  119. package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
  120. package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
  121. package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
  122. package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
  123. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  124. package/dist/mesh/mesh-refine-gates.d.ts +457 -0
  125. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  126. package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
  127. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  128. package/dist/mesh/mesh-routing.d.ts +70 -0
  129. package/dist/mesh/mesh-runtime-store.d.ts +567 -0
  130. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  131. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  132. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  133. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +34 -0
  134. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  135. package/dist/mesh/mesh-work-queue.d.ts +392 -1
  136. package/dist/mesh/preview-freshness.d.ts +28 -0
  137. package/dist/mesh/refine-config.d.ts +97 -0
  138. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  139. package/dist/providers/acp-provider-instance.d.ts +5 -0
  140. package/dist/providers/approval-utils.d.ts +46 -0
  141. package/dist/providers/chat-message-normalization.d.ts +58 -1
  142. package/dist/providers/cli-provider-effect-format.d.ts +30 -0
  143. package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
  144. package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
  145. package/dist/providers/cli-provider-instance-types.d.ts +45 -0
  146. package/dist/providers/cli-provider-instance.d.ts +426 -30
  147. package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
  148. package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
  149. package/dist/providers/contracts.d.ts +196 -6
  150. package/dist/providers/external-sources.d.ts +71 -0
  151. package/dist/providers/manual-attendance.d.ts +79 -0
  152. package/dist/providers/native-history/antigravity-claim-registry.d.ts +39 -0
  153. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  154. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  155. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  156. package/dist/providers/native-history/constants.d.ts +12 -0
  157. package/dist/providers/native-history/dispatcher.d.ts +44 -0
  158. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  159. package/dist/providers/native-history/index.d.ts +13 -0
  160. package/dist/providers/provider-instance-manager.d.ts +30 -0
  161. package/dist/providers/provider-instance.d.ts +31 -1
  162. package/dist/providers/provider-loader.d.ts +42 -5
  163. package/dist/providers/provider-trust.d.ts +31 -0
  164. package/dist/providers/read-chat-contract.d.ts +29 -0
  165. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  166. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  167. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  168. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  169. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  170. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  171. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  172. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  173. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  174. package/dist/providers/sdk/v1/index.d.ts +30 -0
  175. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  176. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  177. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  178. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  179. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  180. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  181. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  182. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  183. package/dist/providers/spec/adapter.d.ts +98 -0
  184. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  185. package/dist/providers/spec/evaluator.d.ts +45 -0
  186. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  187. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  188. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  189. package/dist/providers/spec/fsm-types.d.ts +202 -0
  190. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  191. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  192. package/dist/providers/spec/route.d.ts +4 -0
  193. package/dist/providers/spec/types.d.ts +244 -0
  194. package/dist/providers/status-monitor.d.ts +7 -7
  195. package/dist/providers/transcript-v2.d.ts +176 -0
  196. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  197. package/dist/providers/working-dir.d.ts +17 -0
  198. package/dist/repo-mesh-types.d.ts +616 -12
  199. package/dist/runtime-defaults.d.ts +2 -0
  200. package/dist/session-host/managed-host.d.ts +64 -0
  201. package/dist/session-host/runtime-surface.d.ts +10 -16
  202. package/dist/sessions/registry.d.ts +26 -0
  203. package/dist/shared-types-extra.d.ts +2 -4
  204. package/dist/shared-types.d.ts +110 -55
  205. package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
  206. package/dist/status/normalize.d.ts +1 -1
  207. package/dist/status/normalize.js +1 -0
  208. package/dist/status/normalize.js.map +1 -1
  209. package/dist/status/normalize.mjs +1 -0
  210. package/dist/status/normalize.mjs.map +1 -1
  211. package/dist/status/reporter.d.ts +2 -0
  212. package/dist/status/snapshot.d.ts +27 -0
  213. package/dist/system/hash.d.ts +8 -0
  214. package/dist/system/load-better-sqlite3.d.ts +21 -0
  215. package/dist/types.d.ts +20 -6
  216. package/package.json +11 -4
  217. package/src/agent-stream/poller.ts +2 -3
  218. package/src/agent-stream/provider-adapter.ts +1 -1
  219. package/src/boot/daemon-lifecycle.ts +80 -14
  220. package/src/boot/process-hardening.ts +89 -0
  221. package/src/build-info.ts +73 -0
  222. package/src/chat/source-machine.ts +534 -0
  223. package/src/chat/source-resolver.ts +0 -0
  224. package/src/chat/subscription-updates.ts +20 -1
  225. package/src/cli-adapter-types.d.ts +3 -1
  226. package/src/cli-adapter-types.ts +68 -2
  227. package/src/cli-adapters/cli-script-runner.ts +421 -0
  228. package/src/cli-adapters/cli-state-engine.ts +1282 -0
  229. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  230. package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
  231. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  232. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  233. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  234. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  235. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  236. package/src/cli-adapters/pty-transport.ts +2 -1
  237. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  238. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  239. package/src/cli-adapters/resolve-executable.ts +204 -0
  240. package/src/cli-adapters/session-host-transport.ts +2 -1
  241. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  242. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  243. package/src/cli-adapters/terminal-screen.ts +16 -81
  244. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  245. package/src/commands/chat-commands-read.ts +2788 -0
  246. package/src/commands/chat-commands-scope.ts +54 -0
  247. package/src/commands/chat-commands-shared.ts +114 -0
  248. package/src/commands/chat-commands-write.ts +891 -0
  249. package/src/commands/chat-commands.ts +19 -1841
  250. package/src/commands/cli-manager.d.ts +2 -0
  251. package/src/commands/cli-manager.ts +724 -27
  252. package/src/commands/handler.ts +865 -2
  253. package/src/commands/high-family/index.ts +28 -0
  254. package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
  255. package/src/commands/high-family/mesh-events.ts +102 -0
  256. package/src/commands/high-family/mesh-status.ts +857 -0
  257. package/src/commands/high-family/types.ts +80 -0
  258. package/src/commands/low-family/coordinator-prompt.ts +125 -0
  259. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  260. package/src/commands/low-family/diagnostics.ts +57 -0
  261. package/src/commands/low-family/index.ts +37 -0
  262. package/src/commands/low-family/mesh-ledger.ts +62 -0
  263. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  264. package/src/commands/low-family/notification.ts +116 -0
  265. package/src/commands/low-family/refine-config.ts +106 -0
  266. package/src/commands/low-family/session-host.ts +282 -0
  267. package/src/commands/low-family/spec-providerdev.ts +217 -0
  268. package/src/commands/low-family/status-meta.ts +112 -0
  269. package/src/commands/low-family/types.ts +39 -0
  270. package/src/commands/med-family/cli-agent.ts +270 -0
  271. package/src/commands/med-family/fast-forward.ts +230 -0
  272. package/src/commands/med-family/ide.ts +163 -0
  273. package/src/commands/med-family/index.ts +37 -0
  274. package/src/commands/med-family/mesh-crud.ts +1268 -0
  275. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  276. package/src/commands/med-family/mesh-queue.ts +167 -0
  277. package/src/commands/med-family/mesh-restart.ts +92 -0
  278. package/src/commands/med-family/types.ts +153 -0
  279. package/src/commands/mesh-coordinator.ts +334 -124
  280. package/src/commands/router-aggregate-status.ts +209 -0
  281. package/src/commands/router-mesh-session-owner.ts +114 -0
  282. package/src/commands/router-refine.ts +1794 -0
  283. package/src/commands/router-worktree-cleanup.ts +870 -0
  284. package/src/commands/router.ts +567 -4149
  285. package/src/commands/stream-commands.ts +8 -0
  286. package/src/commands/upgrade-helper.ts +310 -45
  287. package/src/config/chat-history.ts +517 -24
  288. package/src/config/config.ts +30 -0
  289. package/src/config/mesh-config.ts +300 -24
  290. package/src/config/mesh-json-config.ts +376 -0
  291. package/src/config/recent-activity.ts +8 -2
  292. package/src/config/registry-resolver.ts +100 -0
  293. package/src/config/repo-settings.ts +111 -0
  294. package/src/config/state-store.ts +55 -0
  295. package/src/daemon/dev-auto-implement.ts +3 -2
  296. package/src/daemon/dev-cli-debug.ts +10 -1
  297. package/src/daemon/dev-server.ts +0 -541
  298. package/src/detection/cli-detector.ts +94 -9
  299. package/src/detection/ide-detector.ts +55 -16
  300. package/src/detection/win32-ide-version.ts +106 -0
  301. package/src/git/change-impact-config.ts +354 -0
  302. package/src/git/git-commands.ts +112 -16
  303. package/src/git/git-diff.ts +81 -11
  304. package/src/git/git-executor.ts +12 -0
  305. package/src/git/git-status.ts +822 -48
  306. package/src/git/git-types.ts +14 -62
  307. package/src/git/git-worktree.ts +261 -4
  308. package/src/git/index.ts +17 -0
  309. package/src/index.ts +190 -13
  310. package/src/installer.d.ts +1 -1
  311. package/src/installer.ts +8 -6
  312. package/src/ipc/local-ipc-server.ts +278 -0
  313. package/src/launch.d.ts +1 -1
  314. package/src/launch.ts +37 -28
  315. package/src/logging/async-batch-writer.ts +55 -0
  316. package/src/logging/command-log.ts +7 -5
  317. package/src/logging/debug-config.ts +25 -0
  318. package/src/logging/debug-trace.ts +7 -2
  319. package/src/logging/log-redactor.ts +100 -0
  320. package/src/logging/log-tail-reader.ts +341 -0
  321. package/src/logging/logger.ts +14 -7
  322. package/src/mesh/contracts.ts +510 -0
  323. package/src/mesh/coordinator-prompt.ts +627 -34
  324. package/src/mesh/coordinator-registry.ts +121 -0
  325. package/src/mesh/mesh-active-work.ts +706 -0
  326. package/src/mesh/mesh-clone-grace.ts +68 -0
  327. package/src/mesh/mesh-completion-synthesis.ts +416 -0
  328. package/src/mesh/mesh-coordinator-config.ts +97 -0
  329. package/src/mesh/mesh-delivery-policy.ts +284 -0
  330. package/src/mesh/mesh-event-classify.ts +78 -0
  331. package/src/mesh/mesh-event-forwarding.ts +2030 -0
  332. package/src/mesh/mesh-event-trace.ts +67 -0
  333. package/src/mesh/mesh-events-coordinator.ts +32 -0
  334. package/src/mesh/mesh-events-pending.ts +1548 -0
  335. package/src/mesh/mesh-events-stale.ts +452 -0
  336. package/src/mesh/mesh-events-utils.ts +443 -0
  337. package/src/mesh/mesh-events.ts +43 -1035
  338. package/src/mesh/mesh-fast-forward.ts +856 -0
  339. package/src/mesh/mesh-host-ownership.ts +41 -3
  340. package/src/mesh/mesh-init.ts +350 -0
  341. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  342. package/src/mesh/mesh-ledger.ts +897 -102
  343. package/src/mesh/mesh-magi-status.ts +223 -0
  344. package/src/mesh/mesh-missions.ts +695 -0
  345. package/src/mesh/mesh-node-identity.ts +2065 -0
  346. package/src/mesh/mesh-queue-assignment.ts +2498 -0
  347. package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
  348. package/src/mesh/mesh-reconcile-config.ts +66 -0
  349. package/src/mesh/mesh-reconcile-identity.ts +103 -0
  350. package/src/mesh/mesh-reconcile-loop.ts +1696 -0
  351. package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
  352. package/src/mesh/mesh-refine-batch.ts +205 -0
  353. package/src/mesh/mesh-refine-gates.ts +1792 -0
  354. package/src/mesh/mesh-refine-status.ts +231 -0
  355. package/src/mesh/mesh-remote-event-pull.ts +279 -0
  356. package/src/mesh/mesh-review-inbox.ts +308 -0
  357. package/src/mesh/mesh-routing.ts +291 -0
  358. package/src/mesh/mesh-runtime-store.ts +2292 -0
  359. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  360. package/src/mesh/mesh-task-inflight.ts +70 -0
  361. package/src/mesh/mesh-task-stats.ts +161 -0
  362. package/src/mesh/mesh-unresolved-forward-outbox.ts +215 -0
  363. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  364. package/src/mesh/mesh-work-queue.ts +1489 -145
  365. package/src/mesh/preview-freshness.ts +163 -0
  366. package/src/mesh/refine-config.ts +129 -12
  367. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  368. package/src/providers/acp-provider-instance.ts +43 -10
  369. package/src/providers/approval-utils.d.ts +5 -0
  370. package/src/providers/approval-utils.ts +100 -6
  371. package/src/providers/chat-message-normalization.ts +126 -4
  372. package/src/providers/cli-provider-effect-format.ts +53 -0
  373. package/src/providers/cli-provider-history-dedup.ts +75 -0
  374. package/src/providers/cli-provider-input-prompt.ts +133 -0
  375. package/src/providers/cli-provider-instance-types.ts +131 -0
  376. package/src/providers/cli-provider-instance.ts +2771 -499
  377. package/src/providers/cli-provider-status-helpers.ts +123 -0
  378. package/src/providers/cli-provider-transcript-merge.ts +114 -0
  379. package/src/providers/contracts.d.ts +55 -0
  380. package/src/providers/contracts.ts +207 -6
  381. package/src/providers/extension-provider-instance.ts +12 -7
  382. package/src/providers/external-sources.ts +218 -0
  383. package/src/providers/ide-provider-instance.ts +35 -12
  384. package/src/providers/manual-attendance.ts +105 -0
  385. package/src/providers/native-history/antigravity-claim-registry.ts +138 -0
  386. package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -0
  387. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  388. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  389. package/src/providers/native-history/constants.ts +19 -0
  390. package/src/providers/native-history/dispatcher.ts +617 -0
  391. package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
  392. package/src/providers/native-history/index.ts +30 -0
  393. package/src/providers/provider-instance-manager.ts +71 -0
  394. package/src/providers/provider-instance.ts +24 -1
  395. package/src/providers/provider-loader.ts +700 -55
  396. package/src/providers/provider-schema.ts +93 -14
  397. package/src/providers/provider-trust.ts +114 -0
  398. package/src/providers/read-chat-contract.ts +76 -16
  399. package/src/providers/sdk/README.md +49 -0
  400. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  401. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  402. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  403. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  404. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  405. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  406. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  407. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  408. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  409. package/src/providers/sdk/v1/index.ts +152 -0
  410. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  411. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  412. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  413. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +538 -0
  414. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  415. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  416. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  417. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  418. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  419. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  420. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  421. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  422. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  423. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  424. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  425. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  426. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  427. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  428. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  429. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  430. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  431. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  432. package/src/providers/sdk/v1/validators/index.ts +19 -0
  433. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  434. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  435. package/src/providers/spec/adapter.ts +246 -0
  436. package/src/providers/spec/cli-adapter.ts +1064 -0
  437. package/src/providers/spec/evaluator.ts +407 -0
  438. package/src/providers/spec/fsm-driver.ts +1528 -0
  439. package/src/providers/spec/fsm-evaluator.ts +290 -0
  440. package/src/providers/spec/fsm-loader.ts +128 -0
  441. package/src/providers/spec/fsm-types.ts +301 -0
  442. package/src/providers/spec/native-history-executor.ts +1241 -0
  443. package/src/providers/spec/pre-launch-trust.ts +104 -0
  444. package/src/providers/spec/route.ts +51 -0
  445. package/src/providers/spec/types.ts +284 -0
  446. package/src/providers/status-monitor.d.ts +7 -7
  447. package/src/providers/status-monitor.ts +37 -22
  448. package/src/providers/transcript-v2.ts +567 -0
  449. package/src/providers/types/interactive-prompt.ts +536 -0
  450. package/src/providers/version-archive.ts +64 -24
  451. package/src/providers/working-dir.ts +23 -0
  452. package/src/repo-mesh-types.ts +861 -14
  453. package/src/runtime-defaults.ts +39 -0
  454. package/src/session-host/managed-host.ts +218 -0
  455. package/src/session-host/runtime-surface.ts +20 -80
  456. package/src/sessions/registry.ts +44 -0
  457. package/src/shared-types-extra.ts +2 -4
  458. package/src/shared-types.d.ts +8 -0
  459. package/src/shared-types.ts +148 -55
  460. package/src/status/builders.ts +69 -6
  461. package/src/status/chat-tail-hot-sessions.ts +117 -2
  462. package/src/status/normalize.ts +2 -0
  463. package/src/status/reporter.ts +19 -1
  464. package/src/status/snapshot.ts +100 -27
  465. package/src/system/hash.ts +23 -0
  466. package/src/system/host-memory.ts +29 -12
  467. package/src/system/load-better-sqlite3.ts +68 -0
  468. package/src/types.ts +26 -6
  469. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  470. package/dist/mesh/mesh-sync.d.ts +0 -53
  471. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  472. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  473. package/src/mesh/mesh-sync.ts +0 -111
@@ -1,1039 +1,47 @@
1
- import { appendFileSync, existsSync, readFileSync, unlinkSync } from 'fs';
2
- import { join } from 'path';
3
- import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
4
- import { loadConfig } from '../config/config.js';
5
- import { getMesh, getMeshByRepo } from '../config/mesh-config.js';
6
- import { detectCLI } from '../detection/cli-detector.js';
7
- import { LOG } from '../logging/logger.js';
8
- import { appendLedgerEntry, buildTaskCompletionEvidence, getLedgerDir, getSessionRecoveryContext, isIntentionalCleanupStopEntry, readLedgerEntries } from './mesh-ledger.js';
9
- import type { MeshLedgerKind, SessionRecoveryContext } from './mesh-ledger.js';
10
- import { claimNextTask, updateSessionTaskStatus, enqueueTask, updateTaskStatus, getQueue, recordTaskAutoLaunch } from './mesh-work-queue.js';
11
-
12
- // ---------------------------------------------------------------------------
13
- // Remote Node Idle Session Tracking
14
- // ---------------------------------------------------------------------------
15
- // Tracks remote sessions that emitted 'agent:ready' so triggerMeshQueue
16
- // can assign tasks to them. Each entry carries an expiresAt timestamp;
17
- // entries are swept on insertion to prevent unbounded growth.
18
- // ---------------------------------------------------------------------------
19
- interface RemoteIdleSession {
20
- nodeId: string;
21
- sessionId: string;
22
- providerType: string;
23
- expiresAt: number;
24
- }
25
- const REMOTE_IDLE_SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes
26
- const remoteIdleSessions = new Map<string, RemoteIdleSession>(); // key: `${nodeId}:${sessionId}`
27
-
28
- function sweepExpiredRemoteIdleSessions(): void {
29
- const now = Date.now();
30
- for (const [key, session] of remoteIdleSessions) {
31
- if (session.expiresAt <= now) remoteIdleSessions.delete(key);
32
- }
33
- }
34
-
35
1
  // ---------------------------------------------------------------------------
36
- // MCP coordinator pending-event queue FILE-BASED PERSISTENCE
2
+ // mesh-eventsentry point
37
3
  // ---------------------------------------------------------------------------
38
- // When a mesh event fires but no CLI coordinator session is registered (e.g.
39
- // the coordinator is Claude Code running via MCP), we persist the event to a
40
- // per-mesh JSONL file so it survives daemon restarts. The 50-entry hard cap
41
- // is removed; the file is drained atomically on each get_pending_mesh_events
42
- // call and limited to 100 KB to prevent runaway growth.
43
- //
44
- // File: <ledgerDir>/<meshId>.pending-events.jsonl
4
+ // Public API re-exported from sub-modules for backward compatibility.
5
+ // New code should import directly from the relevant sub-module.
45
6
  // ---------------------------------------------------------------------------
46
7
 
47
- export interface PendingMeshCoordinatorEvent {
48
- event: string;
49
- meshId: string;
50
- nodeLabel: string;
51
- nodeId?: string;
52
- workspace?: string;
53
- metadataEvent: Record<string, unknown>;
54
- queuedAt: number;
55
- }
56
-
57
- function getPendingEventsPath(meshId: string): string {
58
- const safe = meshId.replace(/[^a-zA-Z0-9_-]/g, '_');
59
- return join(getLedgerDir(), `${safe}.pending-events.jsonl`);
60
- }
61
-
62
- export function queuePendingMeshCoordinatorEvent(event: PendingMeshCoordinatorEvent): boolean {
63
- try {
64
- appendFileSync(getPendingEventsPath(event.meshId), JSON.stringify(event) + '\n', 'utf-8');
65
- return true;
66
- } catch (e: any) {
67
- LOG.warn('MeshEvents', `Failed to persist pending coordinator event: ${e?.message || e}`);
68
- return false;
69
- }
70
- }
71
-
72
- /** Drain and return all pending coordinator events for meshId, removing them from disk. */
73
- export function drainPendingMeshCoordinatorEvents(meshId?: string): PendingMeshCoordinatorEvent[] {
74
- if (!meshId) return [];
75
- const path = getPendingEventsPath(meshId);
76
- if (!existsSync(path)) return [];
77
- try {
78
- const raw = readFileSync(path, 'utf-8');
79
- try { unlinkSync(path); } catch { /* concurrent drain already removed it */ }
80
- return raw.split('\n').filter(Boolean).flatMap(line => {
81
- try { return [JSON.parse(line) as PendingMeshCoordinatorEvent]; } catch { return []; }
82
- });
83
- } catch { return []; }
84
- }
85
-
86
- /** Peek at pending coordinator events without draining (non-destructive). */
87
- export function getPendingMeshCoordinatorEvents(meshId?: string): readonly PendingMeshCoordinatorEvent[] {
88
- if (!meshId) return [];
89
- const path = getPendingEventsPath(meshId);
90
- if (!existsSync(path)) return [];
91
- try {
92
- const raw = readFileSync(path, 'utf-8');
93
- return raw.split('\n').filter(Boolean).flatMap(line => {
94
- try { return [JSON.parse(line) as PendingMeshCoordinatorEvent]; } catch { return []; }
95
- });
96
- } catch { return []; }
97
- }
98
-
99
- /** Explicitly clear all pending coordinator events for a mesh. */
100
- export function clearPendingMeshCoordinatorEvents(meshId?: string): void {
101
- if (!meshId) return;
102
- const path = getPendingEventsPath(meshId);
103
- if (existsSync(path)) try { unlinkSync(path); } catch { /* already removed */ }
104
- }
105
-
106
- function readNonEmptyString(value: unknown): string {
107
- return typeof value === 'string' && value.trim() ? value.trim() : '';
108
- }
109
-
110
- function resolveEventSessionId(event: Record<string, unknown>, fallback?: unknown): string {
111
- return readNonEmptyString(event.targetSessionId)
112
- || readNonEmptyString(event.sessionId)
113
- || readNonEmptyString(event.instanceId)
114
- || readNonEmptyString(fallback);
115
- }
116
-
117
- const MESH_COORDINATOR_EVENTS = new Set([
118
- 'agent:generating_started',
119
- 'agent:generating_completed',
120
- 'agent:waiting_approval',
121
- 'agent:stopped',
122
- 'agent:ready',
123
- 'monitor:long_generating',
124
- ]);
125
-
126
- const EVENT_TO_LEDGER_KIND: Record<string, MeshLedgerKind> = {
127
- 'agent:generating_completed': 'task_completed',
128
- 'agent:waiting_approval': 'task_approval_needed',
129
- 'agent:stopped': 'task_failed',
130
- 'monitor:long_generating': 'task_stalled',
131
- };
132
-
133
- function isMeshCoordinatorEvent(eventName: unknown): eventName is string {
134
- return typeof eventName === 'string' && MESH_COORDINATOR_EVENTS.has(eventName);
135
- }
136
-
137
- function formatCompletionMetadata(event: Record<string, unknown>): string {
138
- const parts = [
139
- readNonEmptyString(event.targetSessionId) ? `session_id=${readNonEmptyString(event.targetSessionId)}` : '',
140
- readNonEmptyString(event.providerType) ? `provider=${readNonEmptyString(event.providerType)}` : '',
141
- readNonEmptyString(event.providerSessionId) ? `provider_session_id=${readNonEmptyString(event.providerSessionId)}` : '',
142
- ].filter(Boolean);
143
- return parts.length > 0 ? ` (${parts.join('; ')})` : '';
144
- }
145
-
146
- function getMeshWithCache(components: DaemonComponents, meshId: string): any | undefined {
147
- const localMesh = getMesh(meshId);
148
- if (localMesh) return localMesh;
149
- return components.router?.getCachedInlineMesh(meshId);
150
- }
151
-
152
- const INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS = 30 * 60 * 1000;
153
-
154
- function isIntentionalCleanupStopMetadata(event: Record<string, unknown>): boolean {
155
- return event.intentional === true
156
- || event.intentionalStop === true
157
- || event.operatorCleanup === true
158
- || event.reason === 'operator_cleanup'
159
- || event.stopReason === 'operator_cleanup'
160
- || event.cleanupReason === 'operator_cleanup'
161
- || event.source === 'mesh_cleanup_sessions'
162
- || event.source === 'mesh_remove_node';
163
- }
164
-
165
- function hasRecentIntentionalCleanupStop(meshId: string, sessionId?: string, nodeId?: string): boolean {
166
- if (!sessionId && !nodeId) return false;
167
- const cutoff = Date.now() - INTENTIONAL_CLEANUP_STOP_SUPPRESSION_MS;
168
- const entries = readLedgerEntries(meshId);
169
- for (let i = entries.length - 1; i >= 0; i--) {
170
- const entry = entries[i];
171
- const timestamp = new Date(entry.timestamp).getTime();
172
- if (!Number.isNaN(timestamp) && timestamp < cutoff) break;
173
- if (!isIntentionalCleanupStopEntry(entry)) continue;
174
- if (sessionId && entry.sessionId === sessionId) return true;
175
- if (!sessionId && nodeId && entry.nodeId === nodeId) return true;
176
- }
177
- return false;
178
- }
179
-
180
- function shouldSuppressIntentionalCleanupStop(args: {
181
- event: string;
182
- meshId: string;
183
- metadataEvent: Record<string, unknown>;
184
- sessionId?: string;
185
- nodeId?: string;
186
- }): boolean {
187
- if (args.event !== 'agent:stopped' && args.event !== 'monitor:long_generating') return false;
188
- if (isIntentionalCleanupStopMetadata(args.metadataEvent)) return true;
189
- return hasRecentIntentionalCleanupStop(args.meshId, args.sessionId, args.nodeId);
190
- }
191
-
192
- const RECENT_COMPLETION_FINGERPRINT_TTL_MS = 10 * 60 * 1000;
193
- const recentCompletionFingerprints = new Map<string, number>();
194
-
195
- function readEventTimestamp(value: unknown): number | null {
196
- if (typeof value === 'number' && Number.isFinite(value)) return value;
197
- if (typeof value === 'string' && value.trim()) {
198
- const numeric = Number(value);
199
- if (Number.isFinite(numeric)) return numeric;
200
- const parsed = Date.parse(value);
201
- if (Number.isFinite(parsed)) return parsed;
202
- }
203
- return null;
204
- }
205
-
206
- function buildMeshCompletionFingerprint(args: {
207
- meshId: string;
208
- event: string;
209
- sessionId: string;
210
- providerType?: string;
211
- providerSessionId?: string;
212
- timestamp?: number | null;
213
- finalSummary?: string;
214
- }): string {
215
- const timestampPart = Number.isFinite(args.timestamp)
216
- ? String(args.timestamp)
217
- : readNonEmptyString(args.finalSummary).slice(0, 200);
218
- return [
219
- args.meshId,
220
- args.event,
221
- args.sessionId,
222
- args.providerType || '',
223
- args.providerSessionId || '',
224
- timestampPart,
225
- ].join('::');
226
- }
227
-
228
- function isDuplicateMeshCompletionEvent(args: {
229
- meshId: string;
230
- event: string;
231
- sessionId: string;
232
- providerType?: string;
233
- providerSessionId?: string;
234
- timestamp?: number | null;
235
- finalSummary?: string;
236
- }): boolean {
237
- const fingerprint = buildMeshCompletionFingerprint(args);
238
- if (!fingerprint) return false;
239
- const now = Date.now();
240
- for (const [key, seenAt] of recentCompletionFingerprints.entries()) {
241
- if (now - seenAt > RECENT_COMPLETION_FINGERPRINT_TTL_MS) recentCompletionFingerprints.delete(key);
242
- }
243
- if (recentCompletionFingerprints.has(fingerprint)) return true;
244
- recentCompletionFingerprints.set(fingerprint, now);
245
- return false;
246
- }
247
-
248
-
249
- export function tryAssignQueueTask(
250
- components: DaemonComponents,
251
- meshId: string,
252
- nodeId: string,
253
- sessionId: string,
254
- providerType: string
255
- ): boolean {
256
- const task = claimNextTask(meshId, nodeId, sessionId);
257
- if (!task) {
258
- return false;
259
- }
260
-
261
- LOG.info('MeshQueue', `Node ${nodeId} (${sessionId}) pulled task ${task.id}`);
262
-
263
- // Check if the node is remote
264
- const mesh = getMeshWithCache(components, meshId);
265
- const node = mesh?.nodes.find((n: any) => n.id === nodeId);
266
-
267
- // If the node is explicitly remote and we have a dispatch mechanism, route via P2P
268
- if (node?.daemonId && components.dispatchMeshCommand) {
269
- const isLocalNode = components.cliManager.adapters.has(sessionId);
270
- if (!isLocalNode) {
271
- components.dispatchMeshCommand(node.daemonId, 'agent_command', {
272
- targetSessionId: sessionId,
273
- cliType: providerType,
274
- action: 'send_chat',
275
- message: task.message,
276
- }).catch((e: any) => {
277
- LOG.error('MeshQueue', `Failed to dispatch task via P2P to remote node ${nodeId}: ${e?.message}`);
278
- // Revert to pending so the task can be retried rather than permanently failing
279
- updateTaskStatus(meshId, task.id, 'pending');
280
- try {
281
- appendLedgerEntry(meshId, {
282
- kind: 'dispatch_failed' as any,
283
- nodeId,
284
- sessionId,
285
- payload: { taskId: task.id, error: e?.message, retryable: true },
286
- });
287
- } catch { /* ledger write is best-effort */ }
288
- });
289
- return true;
290
- }
291
- }
292
-
293
- // Local routing
294
- components.cliManager.handleCliCommand('agent_command', {
295
- targetSessionId: sessionId,
296
- cliType: providerType,
297
- action: 'send_chat',
298
- message: task.message,
299
- }).catch((e: any) => {
300
- LOG.error('MeshQueue', `Failed to dispatch task locally to node ${nodeId}: ${e?.message}`);
301
- updateTaskStatus(meshId, task.id, 'failed');
302
- });
303
-
304
- return true;
305
- }
306
-
307
- const autoLaunchInProgress = new Set<string>();
308
- const autoLaunchCooldownUntil = new Map<string, number>();
309
- const AUTO_LAUNCH_COOLDOWN_MS = 5_000;
310
-
311
- function normalizeProviderPriority(policy: unknown): string[] {
312
- const raw = policy && typeof policy === 'object' && !Array.isArray(policy)
313
- ? (policy as Record<string, unknown>).providerPriority
314
- : undefined;
315
- if (!Array.isArray(raw)) return [];
316
- const seen = new Set<string>();
317
- return raw
318
- .map(type => typeof type === 'string' ? type.trim() : '')
319
- .filter(Boolean)
320
- .filter(type => {
321
- if (seen.has(type)) return false;
322
- seen.add(type);
323
- return true;
324
- });
325
- }
326
-
327
- function isTerminalSessionStatus(status: string): boolean {
328
- return ['stopped', 'failed', 'terminated', 'exited', 'closed'].includes(status);
329
- }
330
-
331
- function isIdleSessionState(state: any): boolean {
332
- const status = readNonEmptyString(state?.status).toLowerCase();
333
- if (isTerminalSessionStatus(status)) return false;
334
- return status === 'idle' || state?.activeChat?.status === 'waiting_input';
335
- }
336
-
337
- function isDirtyNode(node: any): boolean {
338
- return node?.health === 'dirty' || node?.git?.dirty === true;
339
- }
340
-
341
- function isLaunchableNode(node: any): boolean {
342
- if (!node || node.status === 'disabled' || node.status === 'removed') return false;
343
- const health = readNonEmptyString(node.health).toLowerCase();
344
- if (!health) return true;
345
- return health === 'online' || health === 'unknown';
346
- }
347
-
348
- function localAutoLaunchSkipReason(node: any): string | null {
349
- const daemonId = readNonEmptyString(node?.daemonId);
350
- const machineId = readNonEmptyString(node?.machineId);
351
- const appConfig = loadConfig();
352
- const localMachineId = readNonEmptyString(appConfig.machineId) || readNonEmptyString(appConfig.registeredMachineId);
353
- const cloudDaemonId = localMachineId ? `daemon_${localMachineId}` : '';
354
- const standaloneDaemonId = localMachineId ? `standalone_${localMachineId}` : '';
355
-
356
- const daemonMatchesLocal = !daemonId || daemonId === cloudDaemonId || daemonId === standaloneDaemonId;
357
- const machineMatchesLocal = !machineId || (localMachineId && machineId === localMachineId);
358
-
359
- // ADHDev-managed local worktrees are explicitly safe to launch locally, but
360
- // still must not be auto-launched if their metadata points at another
361
- // daemon/machine. Remote nodes require an explicit coordinator launch path.
362
- if (node?.isLocalWorktree === true) {
363
- return daemonMatchesLocal && machineMatchesLocal ? null : 'remote_auto_launch_unsupported';
364
- }
365
-
366
- // Legacy/local workspace nodes may not have daemon/machine metadata. If
367
- // metadata is present, require it to identify this daemon/machine before
368
- // using the local cliManager.launch_cli path.
369
- if (daemonId || machineId) {
370
- return daemonMatchesLocal && machineMatchesLocal ? null : 'remote_auto_launch_unsupported';
371
- }
372
-
373
- return null;
374
- }
375
-
376
- function activeAssignedCount(meshId: string): number {
377
- return getQueue(meshId, { status: ['assigned'] as any }).length;
378
- }
379
-
380
- function nodeHasActiveAssignment(meshId: string, nodeId: string): boolean {
381
- return getQueue(meshId, { status: ['assigned'] as any }).some(task => task.assignedNodeId === nodeId);
382
- }
383
-
384
- function liveSessionCountForNode(components: DaemonComponents, meshId: string, nodeId: string): number {
385
- return components.instanceManager.getByCategory('cli').filter((inst: any) => {
386
- const state = inst.getState();
387
- const settings = state.settings as Record<string, unknown> || {};
388
- if (readNonEmptyString(settings.meshNodeFor) !== meshId) return false;
389
- const instNodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
390
- if (instNodeId !== nodeId) return false;
391
- const status = readNonEmptyString(state.status).toLowerCase();
392
- return !isTerminalSessionStatus(status);
393
- }).length;
394
- }
395
-
396
- function recordAutoLaunchEvent(meshId: string, args: {
397
- phase: 'skipped' | 'started' | 'failed' | 'completed';
398
- taskId: string;
399
- nodeId?: string;
400
- providerType?: string;
401
- sessionId?: string;
402
- reason?: string;
403
- error?: string;
404
- }) {
405
- try {
406
- appendLedgerEntry(meshId, {
407
- kind: 'session_auto_launch',
408
- nodeId: args.nodeId,
409
- sessionId: args.sessionId,
410
- providerType: args.providerType,
411
- payload: {
412
- phase: args.phase,
413
- taskId: args.taskId,
414
- reason: args.reason,
415
- error: args.error,
416
- },
417
- });
418
- } catch (e: any) {
419
- LOG.warn('MeshQueue', `Failed to record auto-launch ledger event: ${e?.message || e}`);
420
- }
421
- }
422
-
423
- function markAutoLaunch(meshId: string, taskId: string, args: {
424
- status: 'skipped' | 'started' | 'failed' | 'completed';
425
- reason?: string;
426
- nodeId?: string;
427
- providerType?: string;
428
- sessionId?: string;
429
- error?: string;
430
- }) {
431
- recordTaskAutoLaunch(meshId, taskId, {
432
- status: args.status,
433
- reason: args.reason || args.error,
434
- nodeId: args.nodeId,
435
- providerType: args.providerType,
436
- sessionId: args.sessionId,
437
- });
438
- recordAutoLaunchEvent(meshId, {
439
- phase: args.status,
440
- taskId,
441
- nodeId: args.nodeId,
442
- providerType: args.providerType,
443
- sessionId: args.sessionId,
444
- reason: args.reason,
445
- error: args.error,
446
- });
447
- }
448
-
449
- async function resolveUsableProvider(components: DaemonComponents, nodeId: string, node: any): Promise<{ providerType?: string; reason?: string }> {
450
- const providerPriority = normalizeProviderPriority(node?.policy);
451
- if (!providerPriority.length) return { reason: 'missing_provider_priority' };
452
- const providerLoader = components.providerLoader;
453
- if (!providerLoader) return { reason: 'provider_loader_unavailable' };
454
-
455
- const failed: string[] = [];
456
- for (const requestedType of providerPriority) {
457
- const normalizedType = typeof providerLoader.resolveAlias === 'function'
458
- ? providerLoader.resolveAlias(requestedType)
459
- : requestedType;
460
- if (typeof providerLoader.isMachineProviderEnabled === 'function' && !providerLoader.isMachineProviderEnabled(normalizedType)) {
461
- failed.push(`${requestedType}: disabled`);
462
- continue;
463
- }
464
- let detected: any;
465
- try {
466
- detected = await detectCLI(normalizedType, providerLoader, { includeVersion: false });
467
- } catch (e: any) {
468
- failed.push(`${requestedType}: detect failed: ${e?.message || e}`);
469
- continue;
470
- }
471
- if (typeof providerLoader.setCliDetectionResults === 'function') {
472
- providerLoader.setCliDetectionResults([{
473
- id: normalizedType,
474
- installed: !!detected,
475
- path: detected?.path,
476
- }], false);
477
- }
478
- (components as any).onStatusChange?.();
479
- if (detected) return { providerType: normalizedType };
480
- failed.push(`${requestedType}: not detected`);
481
- }
482
- return { reason: `provider_priority_unusable: ${failed.join('; ') || nodeId}` };
483
- }
484
-
485
- async function maybeAutoLaunchOneQueueSession(components: DaemonComponents, meshId: string, mesh: any): Promise<boolean> {
486
- const queue = getQueue(meshId);
487
- const pending = queue.filter(task => task.status === 'pending');
488
- if (!pending.length) return false;
489
-
490
- const maxParallelTasks = Math.max(1, Math.floor(Number(mesh?.policy?.maxParallelTasks) || 2));
491
- for (const task of pending) {
492
- if (activeAssignedCount(meshId) >= maxParallelTasks) {
493
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'max_parallel_tasks_reached' });
494
- return false;
495
- }
496
- if (task.targetSessionId) {
497
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'target_session_constraint' });
498
- continue;
499
- }
500
-
501
- const candidateNodes = Array.isArray(mesh?.nodes)
502
- ? mesh.nodes.filter((node: any) => task.targetNodeId ? node?.id === task.targetNodeId : true)
503
- : [];
504
- if (!candidateNodes.length) {
505
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'no_matching_node', nodeId: task.targetNodeId });
506
- continue;
507
- }
508
-
509
- for (const node of candidateNodes) {
510
- const nodeId = readNonEmptyString(node?.id);
511
- if (!nodeId) continue;
512
- const launchKey = `${meshId}:${nodeId}`;
513
- const cooldownUntil = autoLaunchCooldownUntil.get(launchKey) || 0;
514
- if (autoLaunchInProgress.has(launchKey)) {
515
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'auto_launch_in_progress', nodeId });
516
- continue;
517
- }
518
- if (Date.now() < cooldownUntil) {
519
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'auto_launch_cooldown', nodeId });
520
- continue;
521
- }
522
- if (isDirtyNode(node)) {
523
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'dirty_workspace', nodeId });
524
- continue;
525
- }
526
- if (!isLaunchableNode(node)) {
527
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'node_not_launch_ready', nodeId });
528
- continue;
529
- }
530
- const localSkipReason = localAutoLaunchSkipReason(node);
531
- if (localSkipReason) {
532
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: localSkipReason, nodeId });
533
- continue;
534
- }
535
- if (nodeHasActiveAssignment(meshId, nodeId)) {
536
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'node_has_active_assignment', nodeId });
537
- continue;
538
- }
539
- const maxConcurrentSessions = Number(node?.policy?.maxConcurrentSessions);
540
- if (Number.isFinite(maxConcurrentSessions) && maxConcurrentSessions >= 0 && liveSessionCountForNode(components, meshId, nodeId) >= maxConcurrentSessions) {
541
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: 'max_concurrent_sessions_reached', nodeId });
542
- continue;
543
- }
544
-
545
- autoLaunchInProgress.add(launchKey);
546
- try {
547
- const resolved = await resolveUsableProvider(components, nodeId, node);
548
- if (!resolved.providerType) {
549
- markAutoLaunch(meshId, task.id, { status: 'skipped', reason: resolved.reason || 'provider_unusable', nodeId });
550
- continue;
551
- }
552
-
553
- markAutoLaunch(meshId, task.id, { status: 'started', nodeId, providerType: resolved.providerType });
554
- const launchResult: any = await components.cliManager.handleCliCommand('launch_cli', {
555
- cliType: resolved.providerType,
556
- dir: node.workspace,
557
- settings: {
558
- meshNodeFor: meshId,
559
- meshNodeId: nodeId,
560
- spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || 'hidden',
561
- launchedByCoordinator: true,
562
- autoLaunchedForQueueTaskId: task.id,
563
- },
564
- });
565
- if (!launchResult?.success) {
566
- const reason = launchResult?.error || 'launch_cli_failed';
567
- markAutoLaunch(meshId, task.id, { status: 'failed', reason, nodeId, providerType: resolved.providerType });
568
- autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
569
- return false;
570
- }
571
- const sessionId = readNonEmptyString(launchResult.sessionId) || readNonEmptyString(launchResult.id) || readNonEmptyString(launchResult.runtimeSessionId);
572
- if (!sessionId) {
573
- markAutoLaunch(meshId, task.id, { status: 'failed', reason: 'launch_missing_session_id', nodeId, providerType: resolved.providerType });
574
- autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
575
- return false;
576
- }
577
- markAutoLaunch(meshId, task.id, { status: 'completed', nodeId, providerType: resolved.providerType, sessionId });
578
- tryAssignQueueTask(components, meshId, nodeId, sessionId, resolved.providerType);
579
- return true;
580
- } catch (e: any) {
581
- markAutoLaunch(meshId, task.id, { status: 'failed', error: e?.message || String(e), nodeId });
582
- autoLaunchCooldownUntil.set(launchKey, Date.now() + AUTO_LAUNCH_COOLDOWN_MS);
583
- return false;
584
- } finally {
585
- autoLaunchInProgress.delete(launchKey);
586
- }
587
- }
588
- }
589
- return false;
590
- }
591
-
592
- /**
593
- * Triggers a queue check for all nodes in the mesh.
594
- * Called when a new task is enqueued, in case nodes are already idle.
595
- */
596
- export async function triggerMeshQueue(components: DaemonComponents, meshId: string): Promise<void> {
597
- const mesh = getMeshWithCache(components, meshId);
598
- if (!mesh) return;
599
-
600
- // Find all CLI instances that belong to this mesh and are idle
601
- const cliInstances = components.instanceManager.getByCategory('cli');
602
- for (const inst of cliInstances) {
603
- const state = inst.getState();
604
- const settings = state.settings as Record<string, unknown> || {};
605
-
606
- const instMeshId = readNonEmptyString(settings.meshNodeFor);
607
- if (instMeshId !== meshId) continue;
608
-
609
- const nodeId = readNonEmptyString(settings.meshNodeId) || readNonEmptyString(settings.nodeId);
610
- if (!nodeId) continue;
611
-
612
- // Only genuinely idle live sessions can pull work. Restored/stopped
613
- // records are kept for transcript/recovery visibility, but assigning
614
- // queue items to them strands tasks in assigned/pending without chat.
615
- if (!isIdleSessionState(state)) continue;
616
-
617
- const sessionId = state.instanceId;
618
- const providerType = state.type || readNonEmptyString(settings.providerType);
619
-
620
- if (providerType) {
621
- // Try to assign a task to this idle node
622
- tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType);
623
- }
624
- }
625
-
626
- // Also check known idle remote sessions
627
- for (const [key, idle] of remoteIdleSessions.entries()) {
628
- // Find if this node is in the same mesh
629
- const node = mesh.nodes.find((n: any) => n.id === idle.nodeId);
630
- if (node) {
631
- const assigned = tryAssignQueueTask(components, meshId, idle.nodeId, idle.sessionId, idle.providerType);
632
- if (assigned) {
633
- remoteIdleSessions.delete(key);
634
- }
635
- }
636
- }
637
-
638
- await maybeAutoLaunchOneQueueSession(components, meshId, mesh);
639
- }
640
-
641
- function buildMeshSystemMessage(args: {
642
- event: string;
643
- nodeLabel: string;
644
- metadataEvent: Record<string, unknown>;
645
- recoveryContext?: SessionRecoveryContext | null;
646
- }): string {
647
- const metadata = formatCompletionMetadata(args.metadataEvent);
648
- if (args.event === 'agent:generating_completed') {
649
- return `[System] ${args.nodeLabel} has completed its task and is now idle${metadata}. This completion came from the agent status event path; use mesh_read_chat once to review its final progress, but do not poll repeatedly.`;
650
- }
651
- if (args.event === 'agent:waiting_approval') {
652
- return `[System] ${args.nodeLabel} is waiting for approval to proceed${metadata}. You may use mesh_read_chat and mesh_approve to handle it.`;
653
- }
654
- if (args.event === 'agent:stopped') {
655
- const rc = args.recoveryContext;
656
- if (rc && rc.consecutiveNodeFailures > 0) {
657
- const parts = [
658
- `[System] ${args.nodeLabel} has stopped unexpectedly${metadata}.`,
659
- `\n\n**Recovery Context:**`,
660
- `- Consecutive failures on this node: ${rc.consecutiveNodeFailures}`,
661
- rc.taskAttemptCount > 0 ? `- This task has been attempted ${rc.taskAttemptCount} time(s)` : '',
662
- `- Recommendation: ${rc.advice}`,
663
- ];
664
- if (rc.retryRecommended && rc.lastTaskMessage) {
665
- parts.push(
666
- `\n\n**Original task to retry:**`,
667
- `> ${rc.lastTaskMessage.length > 300 ? rc.lastTaskMessage.slice(0, 300) + '...' : rc.lastTaskMessage}`,
668
- `\nTo retry: call \`mesh_launch_session\` for this node, then \`mesh_send_task\` with the original task.`,
669
- );
670
- } else if (!rc.retryRecommended) {
671
- parts.push(
672
- `\nDo NOT retry on this node. Consider reassigning to a different node or asking the user for guidance.`,
673
- );
674
- }
675
- return parts.filter(Boolean).join('\n');
676
- }
677
- return `[System] ${args.nodeLabel} has stopped${metadata}. Use mesh_read_chat once if you need to inspect its last output.`;
678
- }
679
- if (args.event === 'monitor:long_generating') {
680
- return `[System] ${args.nodeLabel} has been generating for a long time${metadata}. Use mesh_read_chat once for a status check, but do not poll repeatedly.`;
681
- }
682
- return '';
683
- }
684
-
685
- function injectMeshSystemMessage(components: DaemonComponents, args: {
686
- meshId: string;
687
- sourceInstanceId?: string;
688
- nodeId?: string;
689
- nodeLabel: string;
690
- event: string;
691
- metadataEvent: Record<string, unknown>;
692
- }) {
693
- const eventSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
694
- const eventNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
695
- const intentionalCleanupStop = shouldSuppressIntentionalCleanupStop({
696
- event: args.event,
697
- meshId: args.meshId,
698
- metadataEvent: args.metadataEvent,
699
- sessionId: eventSessionId || undefined,
700
- nodeId: eventNodeId || undefined,
701
- });
702
- if (intentionalCleanupStop) {
703
- if (eventSessionId && eventNodeId) {
704
- remoteIdleSessions.delete(`${eventNodeId}:${eventSessionId}`);
705
- }
706
- LOG.info('MeshEvents', `Suppressed ${args.event} for intentionally cleanup-stopped session ${eventSessionId || '(unknown session)'}`);
707
- return { success: true, forwarded: 0, suppressed: true, intentionalCleanupStop: true };
708
- }
709
-
710
- const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
711
- if (args.event === 'agent:generating_completed' && eventSessionId) {
712
- const duplicateCompletion = isDuplicateMeshCompletionEvent({
713
- meshId: args.meshId,
714
- event: args.event,
715
- sessionId: eventSessionId,
716
- providerType: readNonEmptyString(args.metadataEvent.providerType) || undefined,
717
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
718
- timestamp: eventTimestamp,
719
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
720
- });
721
- if (duplicateCompletion) {
722
- LOG.info('MeshEvents', `Suppressed duplicate completion for mesh ${args.meshId} session ${eventSessionId}`);
723
- return { success: true, forwarded: 0, suppressed: true, duplicateCompletion: true };
724
- }
725
- }
726
-
727
- // ── Task Queue & Ledger ──
728
- let completedTaskForLedger: { id?: string } | null = null;
729
- if (args.event === 'agent:generating_completed') {
730
- const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
731
- const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
732
- const providerType = readNonEmptyString(args.metadataEvent.providerType);
733
-
734
- if (sessionId) {
735
- const completedTask = updateSessionTaskStatus(args.meshId, sessionId, 'completed', {
736
- occurredAt: eventTimestamp !== null ? new Date(eventTimestamp).toISOString() : undefined,
737
- });
738
- completedTaskForLedger = completedTask ? { id: completedTask.id } : null;
739
- if (nodeId && providerType) {
740
- // Queue state is already updated above; setImmediate avoids the
741
- // 500 ms artificial delay while still deferring past this call frame.
742
- setImmediate(() => {
743
- tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
744
- });
745
- }
746
- }
747
- } else if (args.event === 'agent:ready') {
748
- const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
749
- const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
750
- const providerType = readNonEmptyString(args.metadataEvent.providerType);
751
- const completedTask = sessionId
752
- ? updateSessionTaskStatus(args.meshId, sessionId, 'completed')
753
- : null;
754
- if (completedTask) {
755
- completedTaskForLedger = { id: completedTask.id };
756
- try {
757
- appendLedgerEntry(args.meshId, {
758
- kind: 'task_completed',
759
- nodeId: nodeId || undefined,
760
- sessionId,
761
- providerType: providerType || undefined,
762
- payload: {
763
- event: args.event,
764
- nodeLabel: args.nodeLabel,
765
- taskId: completedTask.id,
766
- completedViaReady: true,
767
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
768
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
769
- evidence: buildTaskCompletionEvidence({
770
- event: 'agent:ready',
771
- nodeId,
772
- sessionId,
773
- providerType: providerType || undefined,
774
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
775
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
776
- }),
777
- },
778
- });
779
- } catch (e: any) {
780
- LOG.warn('MeshLedger', `Failed to record task_completed from ready: ${e?.message || e}`);
781
- }
782
- }
783
-
784
- if (sessionId && nodeId && providerType) {
785
- sweepExpiredRemoteIdleSessions();
786
- remoteIdleSessions.set(`${nodeId}:${sessionId}`, {
787
- nodeId, sessionId, providerType,
788
- expiresAt: Date.now() + REMOTE_IDLE_SESSION_TTL_MS,
789
- });
790
- setImmediate(() => {
791
- const assigned = tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
792
- if (assigned) remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
793
- });
794
- }
795
- } else if (args.event === 'agent:generating_started') {
796
- const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
797
- const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
798
- if (sessionId && nodeId) {
799
- remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
800
- }
801
- } else if (args.event === 'agent:stopped') {
802
- const sessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId);
803
- const nodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
804
- if (sessionId && nodeId) {
805
- remoteIdleSessions.delete(`${nodeId}:${sessionId}`);
806
- }
807
- if (sessionId) {
808
- updateSessionTaskStatus(args.meshId, sessionId, 'failed');
809
- }
810
- }
811
-
812
- const ledgerKind = EVENT_TO_LEDGER_KIND[args.event];
813
- if (ledgerKind) {
814
- try {
815
- const ledgerNodeId = readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined;
816
- const ledgerSessionId = resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || undefined;
817
- const ledgerProviderType = readNonEmptyString(args.metadataEvent.providerType) || undefined;
818
- const completionEvidence = ledgerKind === 'task_completed' && ledgerNodeId && ledgerSessionId
819
- ? buildTaskCompletionEvidence({
820
- event: 'agent:generating_completed',
821
- nodeId: ledgerNodeId,
822
- sessionId: ledgerSessionId,
823
- providerType: ledgerProviderType,
824
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
825
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
826
- })
827
- : undefined;
828
- appendLedgerEntry(args.meshId, {
829
- kind: ledgerKind,
830
- nodeId: ledgerNodeId,
831
- sessionId: ledgerSessionId,
832
- providerType: ledgerProviderType,
833
- payload: {
834
- event: args.event,
835
- nodeLabel: args.nodeLabel,
836
- taskId: completedTaskForLedger?.id || undefined,
837
- providerSessionId: readNonEmptyString(args.metadataEvent.providerSessionId) || undefined,
838
- finalSummary: readNonEmptyString(args.metadataEvent.finalSummary) || undefined,
839
- evidence: completionEvidence,
840
- },
841
- });
842
- } catch (e: any) {
843
- LOG.warn('MeshLedger', `Failed to record ${ledgerKind}: ${e?.message || e}`);
844
- }
845
- }
846
-
847
- // ── Recovery Context: enrich agent:stopped with retry intelligence ──
848
- let recoveryContext: SessionRecoveryContext | null = null;
849
- if (args.event === 'agent:stopped') {
850
- try {
851
- // Resolve maxTaskRetries from mesh policy
852
- const mesh = getMesh(args.meshId);
853
- const maxRetries = mesh?.policy?.maxTaskRetries ?? 1;
854
-
855
- recoveryContext = getSessionRecoveryContext(args.meshId, {
856
- sessionId: resolveEventSessionId(args.metadataEvent, args.sourceInstanceId) || undefined,
857
- nodeId: readNonEmptyString(args.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId) || undefined,
858
- maxRetries,
859
- });
860
- recoveryContext.failedProviderType = readNonEmptyString(args.metadataEvent.providerType) || null;
861
-
862
- // Record recovery_attempted if retry is recommended
863
- if (recoveryContext.retryRecommended && recoveryContext.consecutiveNodeFailures > 0) {
864
- appendLedgerEntry(args.meshId, {
865
- kind: 'recovery_attempted',
866
- nodeId: recoveryContext.failedNodeId || undefined,
867
- sessionId: recoveryContext.failedSessionId || undefined,
868
- providerType: recoveryContext.failedProviderType || undefined,
869
- payload: {
870
- consecutiveFailures: recoveryContext.consecutiveNodeFailures,
871
- taskAttemptCount: recoveryContext.taskAttemptCount,
872
- retryRecommended: recoveryContext.retryRecommended,
873
- advice: recoveryContext.advice,
874
- },
875
- });
876
-
877
- // Auto-Recovery (Phase 5): Automatically re-enqueue the task and re-launch the session
878
- if (recoveryContext.lastTaskMessage && recoveryContext.failedNodeId && recoveryContext.failedProviderType) {
879
- const autoNodeId = recoveryContext.failedNodeId;
880
- try {
881
- const task = enqueueTask(args.meshId, recoveryContext.lastTaskMessage, {
882
- targetNodeId: autoNodeId
883
- });
884
- LOG.info('MeshRecovery', `Auto-requeued failed task: ${task.id} for node ${autoNodeId}`);
885
-
886
- const node = mesh?.nodes.find(n => n.id === autoNodeId);
887
- if (node) {
888
- components.cliManager.handleCliCommand('launch_cli', {
889
- cliType: recoveryContext.failedProviderType,
890
- dir: node.workspace,
891
- settings: {
892
- meshNodeFor: args.meshId,
893
- meshNodeId: node.id,
894
- spawnedSessionVisibility: mesh?.policy?.spawnedSessionVisibility || 'hidden',
895
- launchedByCoordinator: true,
896
- }
897
- }).catch((e: any) => LOG.error('MeshRecovery', `Failed to auto-relaunch session for ${node.id}: ${e?.message}`));
898
- }
899
- } catch (e: any) {
900
- LOG.warn('MeshRecovery', `Failed to execute auto-recovery: ${e?.message}`);
901
- }
902
- }
903
- }
904
-
905
- LOG.info('MeshRecovery', `Recovery context for ${args.nodeLabel}: ${recoveryContext.advice}`);
906
- } catch (e: any) {
907
- LOG.warn('MeshRecovery', `Failed to build recovery context: ${e?.message || e}`);
908
- }
909
- }
910
-
911
- const coordinatorInstances = components.instanceManager.getByCategory('cli').filter((inst) => {
912
- const instState = inst.getState();
913
- if (instState.settings?.meshCoordinatorFor !== args.meshId) return false;
914
- if (args.sourceInstanceId && instState.instanceId === args.sourceInstanceId) return false;
915
- return true;
916
- });
917
-
918
- if (coordinatorInstances.length === 0) {
919
- // No CLI coordinator session found — buffer for MCP-based coordinators.
920
- if (queuePendingMeshCoordinatorEvent({
921
- event: args.event,
922
- meshId: args.meshId,
923
- nodeLabel: args.nodeLabel,
924
- nodeId: args.nodeId || undefined,
925
- workspace: readNonEmptyString(args.metadataEvent.workspace),
926
- metadataEvent: {
927
- ...args.metadataEvent,
928
- ...(recoveryContext ? { recoveryContext } : {}),
929
- },
930
- queuedAt: Date.now(),
931
- })) {
932
- LOG.info('MeshEvents', `Queued ${args.event} for MCP coordinator (mesh ${args.meshId})`);
933
- }
934
- return { success: true, forwarded: 0 };
935
- }
936
-
937
- const messageText = buildMeshSystemMessage({
938
- event: args.event,
939
- nodeLabel: args.nodeLabel,
940
- metadataEvent: args.metadataEvent,
941
- recoveryContext,
942
- });
943
- if (!messageText) return { success: false, error: 'unsupported mesh event' };
944
-
945
- for (const coord of coordinatorInstances) {
946
- const coordState = coord.getState();
947
- LOG.info('MeshEvents', `Forwarding mesh event to coordinator ${coordState.instanceId}`);
948
- coord.onEvent('send_message', { input: { text: messageText, textFallback: messageText } });
949
- }
950
- return { success: true, forwarded: coordinatorInstances.length };
951
- }
952
-
953
- export function handleMeshForwardEvent(components: DaemonComponents, payload: Record<string, unknown>) {
954
- const eventName = readNonEmptyString(payload.event);
955
- if (!isMeshCoordinatorEvent(eventName)) {
956
- return { success: false, error: 'unsupported mesh event' };
957
- }
958
- const meshId = readNonEmptyString(payload.meshId);
959
- if (!meshId) return { success: false, error: 'meshId required' };
960
-
961
- const nodeId = readNonEmptyString(payload.nodeId);
962
- const workspace = readNonEmptyString(payload.workspace);
963
- const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : 'Remote agent';
964
- return injectMeshSystemMessage(components, {
965
- meshId,
966
- nodeId,
967
- nodeLabel,
968
- event: eventName,
969
- metadataEvent: {
970
- targetSessionId: readNonEmptyString(payload.targetSessionId) || readNonEmptyString(payload.sessionId) || readNonEmptyString(payload.instanceId),
971
- providerType: readNonEmptyString(payload.providerType),
972
- providerSessionId: readNonEmptyString(payload.providerSessionId),
973
- finalSummary: readNonEmptyString(payload.finalSummary) || readNonEmptyString(payload.summary),
974
- ...(payload.timestamp !== undefined ? { timestamp: payload.timestamp } : {}),
975
- intentional: payload.intentional === true,
976
- intentionalStop: payload.intentionalStop === true,
977
- operatorCleanup: payload.operatorCleanup === true,
978
- reason: readNonEmptyString(payload.reason),
979
- stopReason: readNonEmptyString(payload.stopReason),
980
- cleanupReason: readNonEmptyString(payload.cleanupReason),
981
- source: readNonEmptyString(payload.source),
982
- },
983
- });
984
- }
985
-
986
- export function setupMeshEventForwarding(components: DaemonComponents) {
987
- components.instanceManager.onEvent((event) => {
988
- // We only care about lightweight Repo Mesh coordinator control/status hints.
989
- if (!isMeshCoordinatorEvent(event.event)) return;
990
-
991
- const instanceId = readNonEmptyString(event.instanceId);
992
- if (!instanceId) return;
993
-
994
- // Try to find the workspace and mesh metadata of the sub-agent.
995
- const sourceInstance = components.instanceManager.getInstance(instanceId);
996
- if (!sourceInstance || sourceInstance.category !== 'cli') return;
997
- const state = sourceInstance.getState();
998
- const workspace = readNonEmptyString(state.workspace);
999
- if (!workspace) return;
1000
- const settings = state.settings && typeof state.settings === 'object' ? state.settings as Record<string, unknown> : {};
1001
-
1002
- // Coordinator sessions must never inject events into themselves.
1003
- // A coordinator instance carries meshCoordinatorFor but not meshNodeFor/launchedByCoordinator.
1004
- if (readNonEmptyString(settings.meshCoordinatorFor)) return;
1005
-
1006
- const meshIdFromRuntime = readNonEmptyString(settings.meshNodeFor);
1007
-
1008
- // Only forward events for sessions that were explicitly launched as mesh-node delegates
1009
- // (meshNodeFor set by mesh_launch_session) or that carry the launchedByCoordinator flag.
1010
- // Do NOT fall back to workspace-based mesh lookup: that would pick up coordinator sessions
1011
- // and any other CLI session that happens to share the same workspace, causing spurious
1012
- // system-message injection into the coordinator's own conversation.
1013
- const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
1014
- if (!isMeshDelegate) return;
1015
-
1016
- const mesh = meshIdFromRuntime ? getMeshWithCache(components, meshIdFromRuntime) : getMeshByRepo(workspace);
1017
- const meshId = meshIdFromRuntime || readNonEmptyString(mesh?.id);
1018
- if (!meshId) return;
1019
-
1020
- // Determine node label. Inline/cloud meshes may be unavailable here, so preserve runtime node id.
1021
- const targetNode = mesh?.nodes?.find((n: any) => n.workspace === workspace);
1022
- const runtimeNodeId = readNonEmptyString(settings.meshNodeId);
1023
- const resolvedNodeId = targetNode?.id || runtimeNodeId;
1024
- const nodeLabel = targetNode
1025
- ? `Node '${targetNode.id}'`
1026
- : runtimeNodeId
1027
- ? `Node '${runtimeNodeId}'`
1028
- : `Agent at ${workspace}`;
1029
-
1030
- injectMeshSystemMessage(components, {
1031
- meshId,
1032
- sourceInstanceId: instanceId,
1033
- nodeId: resolvedNodeId,
1034
- nodeLabel,
1035
- event: event.event,
1036
- metadataEvent: event,
1037
- });
1038
- });
1039
- }
8
+ export type {
9
+ PendingMeshCoordinatorEvent,
10
+ MeshHeldEventRequeueFilter,
11
+ MeshHeldEventRequeueResult,
12
+ } from './mesh-events-pending.js';
13
+ export {
14
+ queuePendingMeshCoordinatorEvent,
15
+ drainPendingMeshCoordinatorEvents,
16
+ getPendingMeshCoordinatorEvents,
17
+ clearPendingMeshCoordinatorEvents,
18
+ requeueHeldMeshCoordinatorEvents,
19
+ serializeV2EnvelopeToWire,
20
+ readV2EnvelopeFromWire,
21
+ getMeshV2DrainCounters,
22
+ isMeshProtocolV2EnforceEnabled,
23
+ } from './mesh-events-pending.js';
24
+
25
+ export {
26
+ reconcileDirectDispatchCompletionFromTranscript,
27
+ } from './mesh-events-stale.js';
28
+
29
+ export {
30
+ setupMeshReconcileLoop,
31
+ runMeshReconcileTick,
32
+ resolveCoordinatorDrainDeliverability,
33
+ shouldHoldPendingDrainForBusyLocalCoordinator,
34
+ getMeshV2BackstopCounters,
35
+ } from './mesh-reconcile-loop.js';
36
+
37
+ export type { MeshQueueTriggerResult } from './mesh-events-coordinator.js';
38
+ export {
39
+ tryAssignQueueTask,
40
+ isSessionActivelyGenerating,
41
+ triggerMeshQueue,
42
+ handleMeshForwardEvent,
43
+ setupMeshEventForwarding,
44
+ isMeshCoordinatorEvent,
45
+ __resetIdleAutoFastForwardForTests,
46
+ __resetMeshWorkspaceCacheForTests,
47
+ } from './mesh-events-coordinator.js';