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

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 +66 -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 +53556 -19074
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +53380 -19063
  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 +1309 -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
@@ -0,0 +1,68 @@
1
+ import { normalizeMeshNodeId, type MeshNodeIdentified } from '@adhdev/mesh-shared';
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Recently-cloned worktree node grace window
5
+ // ---------------------------------------------------------------------------
6
+ // FALSE-BLOCKER-CLONE-QUEUE: right after mesh_clone_node registers a worktree node, a
7
+ // queue task pinned to that node id (target_node pin) can transiently find NO matching
8
+ // node in the coordinator-owning daemon's mesh view, because:
9
+ // - the clone wrote the node ONLY into the inline mesh cache (med-family clone branch),
10
+ // and that inline entry has not yet PROPAGATED to the coordinator daemon (the clone
11
+ // may have run on the source node's machine and forwarded), and/or
12
+ // - the node's worktree bootstrap (npm install / native-addon repair) is still running,
13
+ // so the claim gate defers anyway.
14
+ // In BOTH cases the unmatch SELF-RESOLVES within ~seconds (observed bootstrap ~2m8s) — it
15
+ // is NOT the permanent `target_node_id_unmatched` routing miss (a removed/dead node) that
16
+ // the actionable-blocker coordinator notification exists for. This registry lets the skip
17
+ // classifier tell the transient case apart from the permanent one: a node id recorded here
18
+ // (within the grace TTL) is a freshly cloned worktree whose unmatch should be reported as a
19
+ // transient, NON-actionable skip rather than paging the coordinator with a false
20
+ // "will NOT clear on its own" blocker.
21
+ //
22
+ // The window is floored well above the observed clone + bootstrap + inline-cache
23
+ // propagation latency so a slow-but-live clone is never misclassified as a permanent
24
+ // unmatch. A genuinely dead/removed node is never recorded here (or its entry has long
25
+ // expired), so its `target_node_id_unmatched` stays correctly actionable.
26
+ export const CLONE_BOOTSTRAP_GRACE_MS = 10 * 60 * 1000;
27
+
28
+ const recentlyClonedNodeExpiry = new Map<string, number>(); // normalized nodeId -> expiry epoch ms
29
+ const MAX_TRACKED_CLONED_NODES = 512;
30
+
31
+ function normalizeNodeIdKey(nodeId: string | undefined | null): string {
32
+ return normalizeMeshNodeId({ id: nodeId ?? undefined } as MeshNodeIdentified) ?? '';
33
+ }
34
+
35
+ /** Record that a worktree node id was just cloned, opening its transient grace window. */
36
+ export function noteRecentlyClonedNode(nodeId: string | undefined | null, nowMs: number = Date.now()): void {
37
+ const key = normalizeNodeIdKey(nodeId);
38
+ if (!key) return;
39
+ recentlyClonedNodeExpiry.set(key, nowMs + CLONE_BOOTSTRAP_GRACE_MS);
40
+ if (recentlyClonedNodeExpiry.size > MAX_TRACKED_CLONED_NODES) {
41
+ // Map iteration is insertion-ordered; the first key is the oldest-inserted entry.
42
+ const oldest = recentlyClonedNodeExpiry.keys().next().value;
43
+ if (oldest !== undefined) recentlyClonedNodeExpiry.delete(oldest);
44
+ }
45
+ }
46
+
47
+ /** True when nodeId was cloned within the grace window (and the entry has not expired). */
48
+ export function isWithinCloneBootstrapGrace(nodeId: string | undefined | null, nowMs: number = Date.now()): boolean {
49
+ const key = normalizeNodeIdKey(nodeId);
50
+ if (!key) return false;
51
+ const expiry = recentlyClonedNodeExpiry.get(key);
52
+ if (expiry === undefined) return false;
53
+ if (nowMs >= expiry) {
54
+ recentlyClonedNodeExpiry.delete(key);
55
+ return false;
56
+ }
57
+ return true;
58
+ }
59
+
60
+ /** Drop a node's grace entry (e.g. once it has fully resolved into the mesh view). */
61
+ export function clearCloneBootstrapGrace(nodeId: string | undefined | null): void {
62
+ const key = normalizeNodeIdKey(nodeId);
63
+ if (key) recentlyClonedNodeExpiry.delete(key);
64
+ }
65
+
66
+ export function __resetCloneBootstrapGraceForTests(): void {
67
+ recentlyClonedNodeExpiry.clear();
68
+ }
@@ -0,0 +1,416 @@
1
+ // ---------------------------------------------------------------------------
2
+ // mesh-completion-synthesis — PHASE-4 transcript completion synth + PHASE-5 auto-prune
3
+ // ---------------------------------------------------------------------------
4
+ // Extracted from mesh-reconcile-loop.ts (A-3 god-module decomposition, pure move,
5
+ // no behavior change). This is the reconcile loop's completion-synthesis core:
6
+ // for every active (non-terminal) direct dispatch this daemon hosts, confirm the
7
+ // worker session is idle and — when a final assistant summary exists but no
8
+ // terminal ledger does — synthesize the missing completion (the acked-hold /
9
+ // death-backstop / fast-track machinery lives here). PHASE-5 auto-prune of orphaned
10
+ // dispatch records rides along, sharing the same live-session probe transports.
11
+ //
12
+ // Depends on mesh-remote-event-pull.ts for the P2P read/probe helpers
13
+ // (unwrapReadChatPayload, readChatPayloadStatus, reprobeWorkerStatus,
14
+ // realTerminalEmitPendingForTask, collectLiveNodesWithSessions). The reconcile
15
+ // loop imports reconcileUnterminatedDirectDispatches + autoPruneStaleDirectDispatches.
16
+ // ---------------------------------------------------------------------------
17
+
18
+ import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
19
+ import type { LocalMeshEntry } from '../repo-mesh-types.js';
20
+ import { LOG } from '../logging/logger.js';
21
+ import { readNonEmptyString } from './mesh-events-utils.js';
22
+ import { traceMeshEventDrop } from './mesh-event-trace.js';
23
+ import { daemonIdsEquivalent } from '@adhdev/mesh-shared';
24
+ import { daemonIdListIncludes } from './mesh-reconcile-identity.js';
25
+ import { getActiveDirectDispatches, getQueue } from './mesh-work-queue.js';
26
+ import { readLedgerEntries } from './mesh-ledger.js';
27
+ import { pruneStaleDirectDispatches } from './mesh-active-work.js';
28
+ import { reconcileDirectDispatchCompletionFromTranscript } from './mesh-events-stale.js';
29
+ import { extractFinalAssistantSummaryEvidence } from '../providers/chat-message-normalization.js';
30
+ import type { ChatMessage } from '../types.js';
31
+ import {
32
+ getMeshV2BackstopCounters,
33
+ recordBackstopFire,
34
+ } from './mesh-reconcile-v2-backstop.js';
35
+ import {
36
+ ACKED_DEATH_CONSECUTIVE_READ_FAILURES,
37
+ resolveAckedDeathDeadlineMs,
38
+ resolveAckedTranscriptFastTrackGraceMs,
39
+ inFlightSynthKey,
40
+ getHoldState,
41
+ setHoldState,
42
+ deleteHoldState,
43
+ rehydrateAckedHoldsForMesh,
44
+ collectHeldSynthKeysForMesh,
45
+ } from './mesh-reconcile-acked-hold.js';
46
+ import {
47
+ unwrapReadChatPayload,
48
+ readChatPayloadStatus,
49
+ reprobeWorkerStatus,
50
+ realTerminalEmitPendingForTask,
51
+ collectLiveNodesWithSessions,
52
+ } from './mesh-remote-event-pull.js';
53
+
54
+ // PHASE 4 helper. For every active (non-terminal) direct dispatch this daemon
55
+ // hosts, confirm the worker session is idle via a read_chat and — if a final
56
+ // assistant summary is present but no terminal ledger exists for that dispatch —
57
+ // synthesize the missing completion through reconcileDirectDispatchCompletionFromTranscript.
58
+ //
59
+ // read_chat is resolved against the target node: a node on THIS daemon is read
60
+ // through the local commandHandler; a remote node is read over P2P via
61
+ // dispatchMeshCommand. Both yield the same { messages, status, providerSessionId }
62
+ // shape. We only synthesize when the session reports idle AND a final assistant
63
+ // message exists — the same evidence bar the MCP poll path uses — so an actively
64
+ // generating worker is never falsely completed. The reconcile itself is idempotent.
65
+ export async function reconcileUnterminatedDirectDispatches(
66
+ components: DaemonComponents,
67
+ mesh: LocalMeshEntry,
68
+ selfIds: string[],
69
+ localDaemonId: string | undefined,
70
+ ): Promise<void> {
71
+ const dispatches = getActiveDirectDispatches(mesh.id);
72
+
73
+ // T2 (B2b): restart rehydration. Reload this mesh's persisted acked-hold rows into
74
+ // the Map cache the first time this process touches the mesh — a hold established
75
+ // before a daemon restart is honored again. Must run BEFORE the prune below so a
76
+ // rehydrated hold for a still-active task is not seen as absent-from-cache and lost.
77
+ rehydrateAckedHoldsForMesh(mesh.id);
78
+
79
+ // Prune the in-flight acked-hold state to the tasks still active in THIS mesh, so a
80
+ // completed/pruned task's state is dropped (both the Map cache AND the store row —
81
+ // the persisted table never grows without bound). Runs even when there are zero
82
+ // active dispatches so a restart that landed after every task terminated still
83
+ // reaps orphaned store rows. Iterate the union of Map keys and store rows so a row
84
+ // that exists ONLY on disk (not yet cached) is pruned too.
85
+ const activeTaskKeys = new Set(
86
+ dispatches
87
+ .map(d => readNonEmptyString(d.taskId))
88
+ .filter(Boolean)
89
+ .map(taskId => inFlightSynthKey(mesh.id, taskId)),
90
+ );
91
+ const heldKeys = collectHeldSynthKeysForMesh(mesh.id);
92
+ for (const key of heldKeys) {
93
+ if (!activeTaskKeys.has(key)) deleteHoldState(key, mesh.id);
94
+ }
95
+
96
+ if (dispatches.length === 0) return; // nothing left to reconcile after the prune
97
+
98
+ const dispatchMeshCommand = components.dispatchMeshCommand;
99
+ const nodeById = new Map(mesh.nodes.map(n => [n.id, n] as const));
100
+
101
+ for (const dispatch of dispatches) {
102
+ const sessionId = readNonEmptyString(dispatch.sessionId);
103
+ const nodeId = readNonEmptyString(dispatch.nodeId);
104
+ const taskId = readNonEmptyString(dispatch.taskId);
105
+ if (!sessionId || !nodeId || !taskId) continue;
106
+
107
+ const node = nodeById.get(nodeId);
108
+ const nodeDaemonId = readNonEmptyString(node?.daemonId);
109
+ // A node is local when it has no daemonId, names this daemon, or actually
110
+ // has a live instance here. Anything else is reached over P2P.
111
+ const isLocalNode = !nodeDaemonId
112
+ || daemonIdListIncludes(selfIds, nodeDaemonId)
113
+ || daemonIdsEquivalent(nodeDaemonId, localDaemonId)
114
+ || !!components.instanceManager.getInstance(sessionId);
115
+
116
+ const providerType = readNonEmptyString(dispatch.providerType);
117
+ const readArgs: Record<string, unknown> = {
118
+ sessionId,
119
+ targetSessionId: sessionId,
120
+ tailLimit: 10,
121
+ ...(node?.workspace ? { workspace: node.workspace } : {}),
122
+ ...(providerType ? { agentType: providerType, providerType } : {}),
123
+ };
124
+
125
+ const synthKey = inFlightSynthKey(mesh.id, taskId);
126
+ const isAcked = dispatch.status === 'acked';
127
+ // T6: which last-resort backstop (if any) drove this synth. Set when the
128
+ // acked-hold fast-track / death-deadline promotes the synth; the counter is
129
+ // bumped only if the synth actually COMMITS (result.reconciled), so a
130
+ // deferred/re-probed-away synth is not miscounted. A never-acked dispatch
131
+ // that reaches the commit is a plain PHASE-4 transcript synthesis.
132
+ let backstopKind: keyof ReturnType<typeof getMeshV2BackstopCounters> | undefined;
133
+
134
+ // R4f: read the worker session. A FAILED read (transport error / success:false / no payload)
135
+ // is no longer silently swallowed for an acked task — it is the liveness side of the
136
+ // death backstop (a). We classify the read result and route an acked failure into the
137
+ // failure counter; a never-acked (or non-acked) failure keeps the old best-effort `continue`.
138
+ let payload: Record<string, unknown> | null = null;
139
+ let readFailed = false;
140
+ try {
141
+ if (isLocalNode) {
142
+ const result = await components.commandHandler.handle('read_chat', readArgs);
143
+ if (result && (result as { success?: boolean }).success === false) {
144
+ readFailed = true;
145
+ } else {
146
+ payload = unwrapReadChatPayload(result);
147
+ }
148
+ } else if (dispatchMeshCommand) {
149
+ const result = await dispatchMeshCommand(nodeDaemonId, 'read_chat', readArgs);
150
+ payload = unwrapReadChatPayload(result);
151
+ if (payload && (payload as { success?: boolean }).success === false) { payload = null; readFailed = true; }
152
+ } else {
153
+ continue; // remote node but no P2P transport — can't read; retry next tick (not a death signal)
154
+ }
155
+ } catch {
156
+ readFailed = true; // session may be gone or node offline
157
+ }
158
+ if (!payload && !readFailed) continue; // null payload that wasn't a hard failure — retry next tick
159
+
160
+ if (readFailed || !payload) {
161
+ // R4f backstop (a) — liveness failure. For a never-acked dispatch there is no in-flight
162
+ // turn to protect, so a read failure is a transient probe blip → retry next tick (old
163
+ // behavior). For an ACKED dispatch that we had previously confirmed live, a streak of
164
+ // consecutive read failures means the worker session genuinely went away mid-turn and
165
+ // will never emit its real completion — count it. The actual terminal cleanup of a
166
+ // gone session is owned by PHASE 2.5 (stranded reclaim) / PHASE 5 (orphan prune); here
167
+ // we only record the death observation and STOP holding so those nets can take over,
168
+ // rather than pinning the row on an indefinite hold for a session that is already gone.
169
+ if (isAcked) {
170
+ const prior = getHoldState(synthKey, mesh.id);
171
+ const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
172
+ const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
173
+ // A read failure breaks the idle-with-final-assistant run → reset the fast-track streak
174
+ // (transcriptIdleSinceMs cleared by omission) so it must re-accumulate from scratch.
175
+ setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
176
+ if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
177
+ LOG.warn('MeshReconcile', `Acked-hold death signal: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read_chat failed ${failures}x consecutively after a live-confirmed ack — worker session presumed gone mid-turn; releasing the indefinite synth hold to the stranded-reclaim / orphan-prune nets`);
178
+ }
179
+ }
180
+ continue; // no readable transcript this tick → cannot synth here; retry / let backstops act
181
+ }
182
+
183
+ // Read succeeded (a conclusive idle/generating status) → the session is reachable: reset the
184
+ // failure streak and mark it live-confirmed-since-ack, so a LATER read failure is recognized
185
+ // as a genuine liveness loss (backstop a) rather than a node that was never reachable. The
186
+ // fast-track idle streak (transcriptIdleSinceMs) is PRESERVED across this reset — it is
187
+ // managed below where the idle + final-assistant signal is actually evaluated.
188
+ const priorHoldState = getHoldState(synthKey, mesh.id);
189
+ setHoldState(synthKey, mesh.id, {
190
+ liveConfirmedSinceAck: true,
191
+ consecutiveReadFailures: 0,
192
+ ...(priorHoldState?.transcriptIdleSinceMs !== undefined ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}),
193
+ });
194
+
195
+ // Only act on a session that has actually settled to idle. A generating /
196
+ // waiting_approval session is mid-turn — synthesizing a completion now would
197
+ // be wrong. (idle is the only status the MCP poll path reconciles too.)
198
+ const nowMs = Date.now();
199
+ if (readChatPayloadStatus(payload) !== 'idle') {
200
+ // Not idle → the worker is genuinely mid-turn (a clear live signal). Keep the
201
+ // live-confirmed flag set (above) but RESET the fast-track idle streak: a turn that
202
+ // resumed generating proves the prior idle was a mid-turn blip, not a settled turn-end.
203
+ setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
204
+ continue;
205
+ }
206
+
207
+ // R4f GENERATING-BOUNDARY (acked-hold): a dispatch whose worker was OBSERVED to start
208
+ // generating (the agent:generating_started ack flipped the row to 'acked') is ALIVE and
209
+ // mid-turn — it WILL eventually emit a real terminal. An `idle` read here is therefore
210
+ // presumed a TRANSIENT mid-turn window (a PTY inter-tool-call settle, or final text already
211
+ // rendered while the lifecycle close lags), NOT a settled completion. We HOLD the synth
212
+ // INDEFINITELY rather than racing the worker's (variable, unbounded) emit latency with a
213
+ // finite timer — the failure mode of R4..R4e. This is safe: when the worker's real emit
214
+ // lands it writes a terminal ledger, and reconcileDirectDispatchCompletionFromTranscript's
215
+ // hasTerminalLedgerAfterDispatch makes any later synth an idempotent no-op, so the real emit
216
+ // always wins no matter how late. The hold is released ONLY by the death backstops:
217
+ // (a) consecutive read failures after a live-confirmed ack (handled above), or
218
+ // (b) the absolute ACKED_DEATH_DEADLINE_MS since the ack — a notification-loss net set FAR
219
+ // above any observed emit latency, so it catches a genuinely-wedged worker / lost emit
220
+ // without racing a normal slow turn.
221
+ // A never-acked dispatch (worker never started) is exempt — no in-flight generation to
222
+ // pre-empt; it keeps the first-idle-tick synth, with the downstream grace + stale-summary
223
+ // guards as its backstops.
224
+ //
225
+ // ACKED-HOLD-IDLE-OVERTRUST: the read is idle. Extract the final-assistant evidence NOW (the
226
+ // same signal the synth below requires) so the fast-track can gate on idle-WITH-final-assistant
227
+ // rather than bare idle. Only when a final visible assistant message is present do we treat
228
+ // this tick as a candidate turn-end and accumulate the fast-track grace streak; a bare idle
229
+ // with no assistant result is the worker still warming up and resets the streak.
230
+ const messages = Array.isArray(payload.messages) ? payload.messages as ChatMessage[] : [];
231
+ const evidence = extractFinalAssistantSummaryEvidence(messages);
232
+
233
+ if (isAcked) {
234
+ const ackedAtMs = Date.parse(readNonEmptyString(dispatch.updatedAt));
235
+ const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
236
+ const deathDeadlineMs = resolveAckedDeathDeadlineMs();
237
+
238
+ // ACKED-HOLD-IDLE-OVERTRUST fast-track. Maintain the continuous idle-with-final-assistant
239
+ // streak. The streak starts (or continues) only while a final visible assistant message is
240
+ // present; a tick with idle-but-no-assistant breaks it (the answer is not yet rendered).
241
+ const holdState = getHoldState(synthKey, mesh.id);
242
+ let fastTrackReady = false;
243
+ if (evidence.finalSummary) {
244
+ const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
245
+ if (holdState && holdState.transcriptIdleSinceMs === undefined) {
246
+ setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
247
+ }
248
+ const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
249
+ const idleHeldMs = nowMs - idleSinceMs;
250
+ if (idleHeldMs >= fastTrackGraceMs) {
251
+ fastTrackReady = true;
252
+ backstopKind = 'ackedHoldFastTrackFired';
253
+ LOG.info('MeshReconcile', `Acked-hold transcript fast-track: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle WITH a final assistant message for ${Math.round(idleHeldMs / 1000)}s continuous (grace ${Math.round(fastTrackGraceMs / 1000)}s) — promoting the synth ahead of the ${Math.round(deathDeadlineMs / 1000)}s death backstop; the worker's real emit was lost/late and a later one no-ops idempotently.`);
254
+ }
255
+ } else if (holdState?.transcriptIdleSinceMs !== undefined) {
256
+ // Idle but no final assistant yet → not a turn-end; reset the streak.
257
+ setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: undefined });
258
+ }
259
+
260
+ // Hold indefinitely UNLESS the fast-track grace was met OR the absolute death deadline is
261
+ // reached. The fast-track is the new fast path in front of the (preserved) 8-min backstop.
262
+ if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
263
+ LOG.info('MeshReconcile', `Acked-hold: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle ${Number.isFinite(sinceAckMs) ? Math.round(sinceAckMs / 1000) + 's' : '∞'} since the generating_started ack — HOLDING synth (worker presumed alive; a later real emit is idempotent). Transcript fast-track promotes at ${Math.round(resolveAckedTranscriptFastTrackGraceMs() / 1000)}s continuous idle-with-final-assistant; death backstop at ${Math.round(deathDeadlineMs / 1000)}s or on consecutive read failures.`);
264
+ continue;
265
+ }
266
+ if (!fastTrackReady) {
267
+ backstopKind = 'ackedHoldDeathDeadlineFired';
268
+ LOG.warn('MeshReconcile', `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1000)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1000)}s) — synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
269
+ }
270
+ }
271
+
272
+ // R4f (auxiliary, was R4e fix 3) — worker-emit priority. Secondary check: if the worker's
273
+ // REAL terminal emit for this task has already arrived in the pending-events queue (queued
274
+ // for delivery to the coordinator) but not yet written a terminal ledger, YIELD — let the
275
+ // genuine emit surface rather than racing it with a synth that would win the taskId-anchored
276
+ // fingerprint dedup and mask it. Under the R4f acked-hold this is now an auxiliary belt-and-
277
+ // suspenders check (the indefinite hold already defers an acked synth); it still guards the
278
+ // never-acked path and the post-death-deadline acked synth from racing an emit caught in
279
+ // flight at synth-commit time.
280
+ if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
281
+ deleteHoldState(synthKey, mesh.id);
282
+ LOG.info('MeshReconcile', `Worker-emit priority: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) has a real terminal completion already queued — yielding synth to the worker's own emit`);
283
+ continue;
284
+ }
285
+
286
+ if (!evidence.finalSummary) continue; // no assistant result yet — nothing to attribute
287
+
288
+ // STALE-SUMMARY guard (modal-parked / reused-session misattribution): a direct
289
+ // dispatch frequently reuses a session that already ran a PRIOR task. read_chat
290
+ // returns the tail of the WHOLE session, so extractFinalAssistantSummaryEvidence
291
+ // picks the latest user-facing assistant message — which, for a task that has
292
+ // barely started (the session momentarily reads idle between turns), is the prior
293
+ // task's final summary. The downstream reconcile proves the summary is after the
294
+ // LEDGER task_dispatched entry; here we additionally have the AUTHORITATIVE per-task
295
+ // dispatchedAt (the dispatch-store row, immune to ledger-ordering quirks), so when
296
+ // the selected transcript message is provably BEFORE this task's own dispatch we
297
+ // refuse it outright — it is a prior task's summary, not this task's output (the
298
+ // 2843ms-duration stale-summary bug where task 2e3f501e copy-pasted 4eca2d9d's
299
+ // summary). When the message carries no usable timestamp we do NOT block here: the
300
+ // downstream reconcile already rejects a non-JSON summary it cannot prove is
301
+ // post-dispatch (transcript_not_proven_after_dispatch), and a structured
302
+ // final_summary_json is self-attributing — so a timeless provider is not
303
+ // over-blocked while the provable-stale case is still caught.
304
+ const dispatchedAtMs = Date.parse(readNonEmptyString(dispatch.dispatchedAt));
305
+ const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? '');
306
+ if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
307
+ LOG.info('MeshReconcile', `Stale-summary guard: skipping transcript reconcile for task ${taskId} on node ${nodeId} (mesh ${mesh.id}) — final assistant message (${evidence.transcriptMessageAt}) predates this task's dispatch (${dispatch.dispatchedAt}); it is a prior task's summary`);
308
+ traceMeshEventDrop('reconcile_stale_summary_before_dispatch', {
309
+ taskId, sessionId, nodeId, meshId: mesh.id, event: 'agent:generating_completed',
310
+ }, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
311
+ continue;
312
+ }
313
+
314
+ // R4f (auxiliary, was R4e fix 2) — live re-probe immediately before committing the synth. A
315
+ // fresh read right now catches a worker that resumed generating since this tick's first read
316
+ // so it is never falsely completed off a stale snapshot. Best-effort: an inconclusive
317
+ // re-probe (transport error/null) falls through to the synth — we already hold a valid idle
318
+ // read from the top of THIS tick, so a re-probe failure must not re-introduce a
319
+ // notification-miss. Under the R4f acked-hold this matters mainly for the never-acked path
320
+ // and the post-death-deadline acked synth (the indefinite hold already deferred a live acked
321
+ // turn); it stays as a final live-state guard at synth-commit time.
322
+ const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
323
+ if (reprobeStatus && reprobeStatus !== 'idle') {
324
+ deleteHoldState(synthKey, mesh.id);
325
+ LOG.info('MeshReconcile', `Live re-probe defer: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read '${reprobeStatus}' at synth-commit time — worker resumed generating; deferring synth to a later tick`);
326
+ continue;
327
+ }
328
+
329
+ const providerSessionId = readNonEmptyString(payload.providerSessionId);
330
+ // COORD-EVENT-MISROUTE (anchor preservation): the coordinator DAEMON anchor for the
331
+ // synthesized completion is the daemon that DISPATCHED the task, NOT this reconcile
332
+ // runner's own daemon. On a REMOTE worker the reconcile loop runs on the WORKER's daemon,
333
+ // so `selfIds` is the worker daemon — stamping it as targetCoordinatorDaemonId corrupts the
334
+ // anchor and (when the real coordinator is on another machine) downgrades the completion to
335
+ // a cross-machine broadcast deliverable to any coordinator. Recover the true anchor:
336
+ // 1. the live worker session's meshCoordinatorDaemonId relay stamp (set at dispatch,
337
+ // the same anchor the worker's own real-emit path reads in mesh-event-forwarding); then
338
+ // 2. leave it to reconcileDirectDispatchCompletionFromTranscript, which recovers the
339
+ // DISPATCHING coordinator daemon from the task_dispatched ledger (authoritative).
340
+ // Only when NEITHER is available do we fall back to selfIds — a genuinely local,
341
+ // single-daemon dispatch where self IS the coordinator daemon (unchanged behaviour).
342
+ const workerSession = components.instanceManager.getInstance(sessionId);
343
+ const workerCoordinatorDaemonId = readNonEmptyString(
344
+ (workerSession?.getState()?.settings as Record<string, unknown> | undefined)?.meshCoordinatorDaemonId,
345
+ );
346
+ const coordinatorDaemonId = workerCoordinatorDaemonId || selfIds.find(id => !!id);
347
+ try {
348
+ const result = reconcileDirectDispatchCompletionFromTranscript({
349
+ meshId: mesh.id,
350
+ nodeId,
351
+ sessionId,
352
+ providerType: providerType || undefined,
353
+ providerSessionId: providerSessionId || undefined,
354
+ taskId,
355
+ finalSummary: evidence.finalSummary,
356
+ ...(evidence.transcriptMessageAt ? { transcriptMessageAt: evidence.transcriptMessageAt } : {}),
357
+ // The ledger-recovered dispatching-coordinator daemon (inside the reconcile fn)
358
+ // takes PRIORITY over this arg; this remains the best-available fallback.
359
+ ...(coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {}),
360
+ source: 'daemon_reconcile_transcript_completion',
361
+ });
362
+ if (result.reconciled) {
363
+ // T6: this synth actually committed → count the last-resort backstop fire.
364
+ // An acked hold routes to the fast-track / death-deadline kind captured
365
+ // above; a never-acked dispatch is a plain PHASE-4 transcript synthesis.
366
+ // Under enforce, recordBackstopFire additionally WARNs (target = 0 fires).
367
+ recordBackstopFire(backstopKind ?? 'phase4SynthesisFired', `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
368
+ LOG.info('MeshReconcile', `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
369
+ }
370
+ } catch (e: any) {
371
+ LOG.warn('MeshReconcile', `Transcript completion reconcile threw for task ${taskId}: ${e?.message || e}`);
372
+ }
373
+ }
374
+ }
375
+
376
+ // PHASE 5 helper. Build the live-node view (mesh.nodes decorated with each node's live
377
+ // session list) and run the shared prune core in execute mode with the conservative age gate.
378
+ //
379
+ // Orphan detection needs the SAME live-session evidence the manual MCP prune uses: a node still
380
+ // in mesh.nodes whose session list no longer contains the dispatched sessionId is "session not
381
+ // present" (prunable); a node missing from mesh.nodes entirely is "node no longer in live mesh"
382
+ // (prunable). We obtain live sessions per node via get_status_metadata — local nodes through the
383
+ // local commandHandler, remote nodes over P2P (dispatchMeshCommand) — exactly the transports
384
+ // PHASE 4 already uses. A node we cannot probe (offline) keeps an empty session list; combined
385
+ // with the age gate that only matters once the orphan is genuinely old.
386
+ //
387
+ // O(1) fast exit: when there are no active direct dispatches at all there is nothing to prune,
388
+ // so we skip the (per-node) status probes entirely — an idle mesh costs one indexed query.
389
+ export async function autoPruneStaleDirectDispatches(
390
+ components: DaemonComponents,
391
+ mesh: LocalMeshEntry,
392
+ selfIds: string[],
393
+ localDaemonId: string | undefined,
394
+ minAgeMs: number,
395
+ ): Promise<void> {
396
+ const directDispatches = getActiveDirectDispatches(mesh.id);
397
+ if (directDispatches.length === 0) return; // nothing dispatched → nothing to prune
398
+
399
+ const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
400
+
401
+ const result = pruneStaleDirectDispatches({
402
+ meshId: mesh.id,
403
+ queue: getQueue(mesh.id),
404
+ ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
405
+ directDispatches,
406
+ nodes: liveNodes,
407
+ execute: true,
408
+ minAgeMs,
409
+ source: 'daemon_reconcile_auto_prune',
410
+ });
411
+
412
+ // Log only when something was actually pruned — silence on the common no-op tick.
413
+ if (result.prunedCount > 0) {
414
+ LOG.info('MeshReconcile', `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
415
+ }
416
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Hermes / MCP coordinator config helpers
3
+ *
4
+ * Extracted from commands/router.ts (behavior-preserving move). Contains the
5
+ * MCP-server config parse/serialize helpers and the Hermes coordinator base
6
+ * config loading / temp-override stripping / credential-copy helpers.
7
+ *
8
+ * router.ts re-exports every public symbol from here so existing import paths
9
+ * keep working.
10
+ */
11
+
12
+ import { LOG } from '../logging/logger.js';
13
+ import * as yaml from 'js-yaml';
14
+ import { homedir } from 'os';
15
+ import { join as pathJoin, resolve as pathResolve } from 'path';
16
+ import * as fs from 'fs';
17
+ import type { MeshCoordinatorConfigFormat } from './mesh-refine-gates.js';
18
+
19
+ function loadYamlModule(): { load: (input: string) => any; dump: (input: any, options?: Record<string, any>) => string } {
20
+ return yaml as { load: (input: string) => any; dump: (input: any, options?: Record<string, any>) => string };
21
+ }
22
+
23
+ export function getMcpServersKey(format: MeshCoordinatorConfigFormat): 'mcpServers' | 'mcp_servers' {
24
+ return format === 'hermes_config_yaml' ? 'mcp_servers' : 'mcpServers';
25
+ }
26
+
27
+ export function parseMeshCoordinatorMcpConfig(text: string, format: MeshCoordinatorConfigFormat): Record<string, any> {
28
+ if (!text.trim()) return {};
29
+ if (format === 'claude_mcp_json') return JSON.parse(text);
30
+ const parsed = loadYamlModule().load(text);
31
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
32
+ }
33
+
34
+ export function serializeMeshCoordinatorMcpConfig(config: Record<string, any>, format: MeshCoordinatorConfigFormat): string {
35
+ if (format === 'claude_mcp_json') return JSON.stringify(config, null, 2);
36
+ return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
37
+ }
38
+
39
+ function resolveHermesUserHome(): string {
40
+ const explicitHome = process.env.HERMES_HOME?.trim();
41
+ return explicitHome || pathJoin(homedir(), '.hermes');
42
+ }
43
+
44
+ export function loadHermesCoordinatorBaseConfig(targetConfigPath: string): { config: Record<string, any>; sourceHome: string; sourceConfigPath: string } {
45
+ const sourceHome = resolveHermesUserHome();
46
+ const sourceConfigPath = pathJoin(sourceHome, 'config.yaml');
47
+ if (!fs.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
48
+ if (pathResolve(sourceConfigPath) === pathResolve(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
49
+
50
+ const parsed = parseMeshCoordinatorMcpConfig(fs.readFileSync(sourceConfigPath, 'utf-8'), 'hermes_config_yaml');
51
+ const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
52
+ return { config: baseConfig, sourceHome, sourceConfigPath };
53
+ }
54
+
55
+ export function stripHermesCoordinatorTempModelProviderOverrides(config: Record<string, any>): Record<string, any> {
56
+ const {
57
+ model: _model,
58
+ provider: _provider,
59
+ default_model: _defaultModel,
60
+ defaultProvider: _defaultProvider,
61
+ default_provider: _defaultProviderSnake,
62
+ modelProvider: _modelProvider,
63
+ model_provider: _modelProviderSnake,
64
+ ...sanitized
65
+ } = config;
66
+ const delegation = sanitized.delegation;
67
+ if (delegation && typeof delegation === 'object' && !Array.isArray(delegation)) {
68
+ const {
69
+ model: _delegationModel,
70
+ provider: _delegationProvider,
71
+ modelProvider: _delegationModelProvider,
72
+ model_provider: _delegationModelProviderSnake,
73
+ ...delegationRest
74
+ } = delegation;
75
+ if (Object.keys(delegationRest).length > 0) {
76
+ sanitized.delegation = delegationRest;
77
+ } else {
78
+ delete sanitized.delegation;
79
+ }
80
+ }
81
+ return sanitized;
82
+ }
83
+
84
+ export function copyHermesCoordinatorCredentialFiles(sourceHome: string, targetHome: string) {
85
+ if (pathResolve(sourceHome) === pathResolve(targetHome)) return;
86
+ for (const fileName of ['.env', 'auth.json']) {
87
+ const sourcePath = pathJoin(sourceHome, fileName);
88
+ const targetPath = pathJoin(targetHome, fileName);
89
+ if (!fs.existsSync(sourcePath)) continue;
90
+ try {
91
+ fs.copyFileSync(sourcePath, targetPath);
92
+ } catch (error: any) {
93
+ LOG.warn('MeshCoordinator', `Could not copy Hermes ${fileName} into isolated coordinator home: ${error?.message || error}`);
94
+ }
95
+ }
96
+ }
97
+