@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
@@ -18,13 +18,15 @@ import { loadConfig } from '../config/config.js';
18
18
  import { loadState, saveState } from '../config/state-store.js';
19
19
  import { getWorkspaceState, resolveLaunchDirectory } from '../config/workspaces.js';
20
20
  import { appendRecentActivity } from '../config/recent-activity.js';
21
+ import { shortHash } from '../system/hash.js';
22
+ import { unregisterMeshCoordinator, getCoordinatorForSession, listCoordinatorsForWorkspace } from '../mesh/coordinator-registry.js';
21
23
  import { upsertSavedProviderSession } from '../config/saved-sessions.js';
22
24
  import { buildLegacyModelModeSummaryMetadata, normalizeProviderSummaryMetadata } from '../providers/summary-metadata.js';
23
25
  import { CliProviderInstance } from '../providers/cli-provider-instance.js';
24
26
  import { AcpProviderInstance } from '../providers/acp-provider-instance.js';
25
27
  import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
26
28
  import { ProviderLoader } from '../providers/provider-loader.js';
27
- import { normalizeInputEnvelope, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
29
+ import { normalizeInputEnvelope, type MeshCoordinatorDelegatedWorkerIsolation, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
28
30
  import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
29
31
  import type { CliAdapter } from '../cli-adapter-types.js';
30
32
  import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
@@ -80,6 +82,126 @@ export interface CliManagerDeps {
80
82
 
81
83
  type CommandResult = { success: boolean;[key: string]: unknown };
82
84
 
85
+ const BUSY_AGENT_STATUSES = new Set(['generating', 'running', 'streaming', 'starting', 'busy', 'waiting', 'waiting_approval', 'no_progress', 'long_generating']);
86
+ const ZERO_MESSAGE_STARTING_SEND_WAIT_MS = 2_000;
87
+
88
+ function normalizeAgentStatus(value: unknown): string {
89
+ return typeof value === 'string' ? value.trim().toLowerCase() : '';
90
+ }
91
+
92
+ function hasNonEmptyModalButtons(activeModal: unknown): boolean {
93
+ const buttons = (activeModal as any)?.buttons;
94
+ return Array.isArray(buttons) && buttons.some((button) => String(button || '').trim().length > 0);
95
+ }
96
+
97
+ function hasAdapterPendingResponse(adapter: any): boolean {
98
+ if (adapter?.isWaitingForResponse === true) return true;
99
+ if (adapter?.currentTurnScope) return true;
100
+ try {
101
+ if (typeof adapter?.isProcessing === 'function' && adapter.isProcessing()) return true;
102
+ } catch { /* defensive: send guard should not fail on diagnostics */ }
103
+ try {
104
+ const partial = typeof adapter?.getPartialResponse === 'function' ? adapter.getPartialResponse() : '';
105
+ if (typeof partial === 'string' && partial.trim()) return true;
106
+ } catch { /* defensive: missing partial means no pending evidence */ }
107
+ return false;
108
+ }
109
+
110
+ function countMessages(value: unknown): number {
111
+ return Array.isArray(value) ? value.length : 0;
112
+ }
113
+
114
+ function hasFinalAssistantMessage(value: unknown): boolean {
115
+ const messages = Array.isArray(value) ? value : [];
116
+ const last = messages[messages.length - 1] as any;
117
+ if (!last || last.role !== 'assistant') return false;
118
+ if (last.bubbleState === 'streaming') return false;
119
+ if (last.meta?.streaming === true) return false;
120
+ return typeof last.content === 'string' && last.content.trim().length > 0;
121
+ }
122
+
123
+ function hasZeroMessageStartingLaunch(adapter: any): boolean {
124
+ const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
125
+ const parsedStatus = typeof adapter?.getScriptParsedStatus === 'function'
126
+ ? adapter.getScriptParsedStatus()
127
+ : {};
128
+ const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
129
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
130
+ if (adapterRawStatus !== 'starting') return false;
131
+ if (parsedRawStatus && parsedRawStatus !== 'starting' && parsedRawStatus !== 'generating') return false;
132
+ if (hasNonEmptyModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
133
+ if (countMessages(adapterStatus?.messages) > 0 || countMessages(parsedStatus?.messages) > 0) return false;
134
+ return !hasAdapterPendingResponse(adapter);
135
+ }
136
+
137
+ function hasCompletedStartingLaunch(adapter: any): boolean {
138
+ const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
139
+ const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
140
+ if (adapterRawStatus !== 'starting') return false;
141
+ if (hasAdapterPendingResponse(adapter)) return false;
142
+
143
+ const parsedStatus = typeof adapter?.getScriptParsedStatus === 'function'
144
+ ? adapter.getScriptParsedStatus()
145
+ : {};
146
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
147
+ if (parsedRawStatus !== 'idle') return false;
148
+ if (hasNonEmptyModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
149
+ return hasFinalAssistantMessage(parsedStatus?.messages);
150
+ }
151
+
152
+ /**
153
+ * WTCLAIM (B): compare two workspace paths for node scoping. Normalizes separator
154
+ * style, trailing slashes, and case (Windows paths are case-insensitive; the
155
+ * coordinator-supplied node.workspace and the adapter's launch workingDir can
156
+ * differ only in those) so a base node and a worktree clone are still told apart
157
+ * by their distinct workspace roots.
158
+ */
159
+ function normalizeDirForCompare(dir?: string): string {
160
+ if (typeof dir !== 'string') return '';
161
+ return dir.trim().replace(/[\\/]+/g, '/').replace(/\/+$/, '').toLowerCase();
162
+ }
163
+
164
+ function shouldSuppressStaleParsedBusyStatus(adapterStatus: string, parsedStatus: any, adapter: any): boolean {
165
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
166
+ if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
167
+ if (adapterStatus !== 'idle') return false;
168
+ if (hasNonEmptyModalButtons(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
169
+ return !hasAdapterPendingResponse(adapter);
170
+ }
171
+
172
+ function getEffectiveAgentSendStatus(adapter: any): string {
173
+ const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
174
+ if (adapterStatus === 'starting' && hasCompletedStartingLaunch(adapter)) return 'idle';
175
+ if (adapterStatus && adapterStatus !== 'idle') return adapterStatus;
176
+ if (adapterStatus !== 'idle') return adapterStatus;
177
+
178
+ if (typeof adapter?.getScriptParsedStatus !== 'function') return adapterStatus;
179
+ try {
180
+ const parsedStatus = adapter.getScriptParsedStatus();
181
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
182
+ if (BUSY_AGENT_STATUSES.has(parsedRawStatus) && !shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter)) {
183
+ return parsedRawStatus;
184
+ }
185
+ } catch {
186
+ return adapterStatus;
187
+ }
188
+ return adapterStatus;
189
+ }
190
+
191
+ async function waitForZeroMessageStartingLaunch(adapter: any): Promise<boolean> {
192
+ try {
193
+ if (!hasZeroMessageStartingLaunch(adapter)) return false;
194
+ } catch {
195
+ return false;
196
+ }
197
+ await new Promise(resolve => setTimeout(resolve, ZERO_MESSAGE_STARTING_SEND_WAIT_MS));
198
+ try {
199
+ return hasZeroMessageStartingLaunch(adapter);
200
+ } catch {
201
+ return false;
202
+ }
203
+ }
204
+
83
205
  export interface CliTransportFactoryParams {
84
206
  runtimeId: string;
85
207
  providerType: string;
@@ -87,6 +209,16 @@ export interface CliTransportFactoryParams {
87
209
  cliArgs?: string[];
88
210
  providerSessionId?: string;
89
211
  attachExisting?: boolean;
212
+ /**
213
+ * Launch-time record meta (meshNodeId / meshNodeFor / launchedByCoordinator /
214
+ * autoLaunchedForQueueTaskId). Defense-in-depth for SESSION-ACCUMULATION-LEAK:
215
+ * a session-host factory impl SHOULD seed the create_session record with this
216
+ * so the node binding is present the instant the record exists, rather than
217
+ * relying solely on the post-spawn updateRuntimeMeta round-trip. Optional and
218
+ * additive — factory impls that ignore it keep the prior behavior; the
219
+ * post-spawn WTDISPATCH stamp in register() still runs as the primary path.
220
+ */
221
+ initialMeta?: Record<string, unknown>;
90
222
  }
91
223
 
92
224
  export interface HostedCliRuntimeDescriptor {
@@ -101,6 +233,14 @@ export interface HostedCliRuntimeDescriptor {
101
233
  cliArgs?: string[];
102
234
  providerSessionId?: string;
103
235
  managedBy?: string;
236
+ /**
237
+ * Real spawn time (ms epoch) of the underlying session-host runtime — a PAST
238
+ * timestamp recorded when the runtime first started. Threaded through so an
239
+ * attach can restore the native-history session-floor to the runtime's actual
240
+ * birth instead of collapsing spawnedAtMs to 0. Undefined when unrecoverable
241
+ * (genuine post-restart-unknown), in which case the caller keeps the 0 fallback.
242
+ */
243
+ startedAtMs?: number;
104
244
  }
105
245
 
106
246
  type CliPresentationInstance = ProviderInstance & {
@@ -136,20 +276,25 @@ type CliStartOptions = {
136
276
  resumeSessionId?: string;
137
277
  settingsOverride?: Record<string, any>;
138
278
  extraEnv?: Record<string, string>;
279
+ /** BRAIN-ROUTING thinking axis: standard level ('low'|'medium'|'high') applied
280
+ * at launch via the provider's thinkingLaunchArgs (CLI) or setConfigOption
281
+ * ('thought_level', ACP). Best-effort — ignored by providers with no support. */
282
+ initialThinkingLevel?: string;
139
283
  };
140
284
 
141
- const COORDINATOR_DELEGATED_ENV_UNSETS: Record<string, string> = {
142
- ADHDEV_INLINE_MESH: '',
143
- ADHDEV_MCP_TRANSPORT: '',
144
- ADHDEV_MESH_ID: '',
145
- HERMES_EPHEMERAL_SYSTEM_PROMPT: '',
146
- };
285
+ const DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS = [
286
+ 'ADHDEV_INLINE_MESH',
287
+ 'ADHDEV_MCP_TRANSPORT',
288
+ 'ADHDEV_MESH_ID',
289
+ 'HERMES_EPHEMERAL_SYSTEM_PROMPT',
290
+ ] as const;
147
291
 
148
292
  export interface CoordinatorDelegatedCliLaunchOptionsInput {
149
293
  cliType: string;
150
294
  workspace: string;
151
295
  cliArgs?: string[];
152
296
  env?: Record<string, string>;
297
+ isolation?: MeshCoordinatorDelegatedWorkerIsolation;
153
298
  }
154
299
 
155
300
  export interface CoordinatorDelegatedCliLaunchOptions {
@@ -161,10 +306,52 @@ function hasCliArg(args: string[], flag: string): boolean {
161
306
  return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
162
307
  }
163
308
 
309
+ /**
310
+ * Decide the session-registry spawnedAtMs (the native-history session-floor) for a
311
+ * newly registered CLI instance.
312
+ *
313
+ * - Fresh launch (attachExisting=false): now (nowMs). A real live spawn floor
314
+ * isolates a fresh session's own store and holds prior-session leak protection.
315
+ * - Attach WITH a recoverable record startedAt (a PAST timestamp): that startedAt.
316
+ * Restoring a hosted runtime (coordinator / MAGI replica / hermes / claude /
317
+ * codex) after a daemon restart, the real spawn time is in the past. Using it
318
+ * restores each session's per-session birth-floor so co-located antigravity
319
+ * runtimes resolve their OWN conversation (ownerConfirmed) instead of the
320
+ * floor-less newest-by-mtime path that let a replica claim the coordinator's conv.
321
+ * - Attach with NO recoverable startedAt: 0 — disables the floor for this session
322
+ * (recent_window_ms still bounds the look-back). NEVER use nowMs here: nowMs is in
323
+ * the FUTURE relative to existing transcripts and would push the floor past every
324
+ * transcript file, losing them (the ANTIGRAVITY-FINAL-MESSAGE-TAIL-GAP regression).
325
+ */
326
+ export function resolveHostedSpawnedAtMs(
327
+ attachExisting: boolean,
328
+ attachStartedAtMs: number | undefined,
329
+ nowMs: number,
330
+ ): number {
331
+ if (!attachExisting) return nowMs;
332
+ if (typeof attachStartedAtMs === 'number' && attachStartedAtMs > 0) return attachStartedAtMs;
333
+ return 0;
334
+ }
335
+
336
+ function hasConfigOverride(args: string[], key: string): boolean {
337
+ for (let index = 0; index < args.length; index += 1) {
338
+ const arg = args[index];
339
+ const next = args[index + 1];
340
+ if ((arg === '-c' || arg === '--config') && typeof next === 'string') {
341
+ if (next === key || next.startsWith(`${key}=`) || next.startsWith(`${key}.`)) return true;
342
+ }
343
+ if (arg.startsWith('--config=')) {
344
+ const value = arg.slice('--config='.length);
345
+ if (value === key || value.startsWith(`${key}=`) || value.startsWith(`${key}.`)) return true;
346
+ }
347
+ }
348
+ return false;
349
+ }
350
+
164
351
  function ensureEmptyDelegatedMcpConfig(workspace: string): string {
165
352
  const baseDir = path.join(os.tmpdir(), 'adhdev-delegated-agent-empty-mcp');
166
353
  mkdirSync(baseDir, { recursive: true });
167
- const workspaceHash = crypto.createHash('sha256').update(path.resolve(workspace || os.tmpdir())).digest('hex').slice(0, 16);
354
+ const workspaceHash = shortHash(path.resolve(workspace || os.tmpdir()));
168
355
  const filePath = path.join(baseDir, `${workspaceHash}.json`);
169
356
  writeFileSync(filePath, JSON.stringify({ mcpServers: {} }, null, 2), 'utf-8');
170
357
  return filePath;
@@ -173,12 +360,31 @@ function ensureEmptyDelegatedMcpConfig(workspace: string): string {
173
360
  export function buildCoordinatorDelegatedCliLaunchOptions(
174
361
  input: CoordinatorDelegatedCliLaunchOptionsInput,
175
362
  ): CoordinatorDelegatedCliLaunchOptions {
176
- const cliType = String(input.cliType || '').trim();
177
363
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
178
- const env: Record<string, string> = { ...(input.env || {}), ...COORDINATOR_DELEGATED_ENV_UNSETS };
364
+ const env: Record<string, string> = { ...(input.env || {}) };
365
+ const envUnsets = new Set<string>(DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS);
366
+ for (const key of input.isolation?.env?.unset || []) {
367
+ if (typeof key === 'string' && key.trim()) envUnsets.add(key.trim());
368
+ }
369
+ for (const key of envUnsets) env[key] = '';
179
370
 
180
- if (cliType === 'claude-cli' && !hasCliArg(cliArgs, '--mcp-config')) {
181
- cliArgs.unshift('--mcp-config', ensureEmptyDelegatedMcpConfig(input.workspace));
371
+ for (const rule of input.isolation?.args || []) {
372
+ if (!rule || typeof rule !== 'object') continue;
373
+ if (rule.mode === 'empty_mcp_config') {
374
+ if (rule.flag && !hasCliArg(cliArgs, rule.flag)) {
375
+ cliArgs.unshift(rule.flag, ensureEmptyDelegatedMcpConfig(input.workspace));
376
+ }
377
+ if (rule.strictFlag && !hasCliArg(cliArgs, rule.strictFlag)) {
378
+ cliArgs.unshift(rule.strictFlag);
379
+ }
380
+ continue;
381
+ }
382
+ if (rule.mode === 'config_override') {
383
+ const key = String(rule.dedupeKey || rule.key || '').trim();
384
+ const flag = String(rule.flag || '').trim();
385
+ if (!key || !flag || hasConfigOverride(cliArgs, key)) continue;
386
+ cliArgs.unshift(flag, `${rule.key}=${rule.value}`);
387
+ }
182
388
  }
183
389
 
184
390
  return { cliArgs, env };
@@ -212,6 +418,40 @@ function expandResumeArgs(template: string[] | undefined, sessionId: string): st
212
418
  return template.map((part) => part === '{{id}}' ? sessionId : part);
213
419
  }
214
420
 
421
+ /**
422
+ * Expand a provider's `modelLaunchArgs` template with the requested model, mirroring
423
+ * expandResumeArgs. `{{model}}` → the trimmed model string. Returns undefined when
424
+ * there is no template or no model (a model request without a template is a no-op —
425
+ * see startSession, where the caller logs the skip). MAGI kind-panel model axis.
426
+ */
427
+ export function expandModelLaunchArgs(template: string[] | undefined, model: string | undefined): string[] | undefined {
428
+ const m = typeof model === 'string' ? model.trim() : '';
429
+ if (!m || !Array.isArray(template) || template.length === 0) return undefined;
430
+ // Substitute {{model}} anywhere in a token, not only when it is the whole token,
431
+ // so templates like ['-c', 'model={{model}}'] (codex) expand as well as the
432
+ // standalone ['--model', '{{model}}'] (claude) form.
433
+ return template.map((part) => part.includes('{{model}}') ? part.split('{{model}}').join(m) : part);
434
+ }
435
+
436
+ /**
437
+ * Expand a provider's `thinkingLaunchArgs` template with the requested thinking
438
+ * level, parallel to expandModelLaunchArgs. The standard level ('low'|'medium'|
439
+ * 'high') is first mapped through the provider's `thinkingLevelMap` (a level absent
440
+ * from the map passes through unchanged), then substituted into every `{{level}}`
441
+ * token. Returns undefined when there is no template or no level (best-effort; a
442
+ * thinking request without a template is a no-op). BRAIN-ROUTING thinking axis.
443
+ */
444
+ export function expandThinkingLaunchArgs(
445
+ template: string[] | undefined,
446
+ level: string | undefined,
447
+ levelMap: Partial<Record<string, string>> | undefined,
448
+ ): string[] | undefined {
449
+ const raw = typeof level === 'string' ? level.trim() : '';
450
+ if (!raw || !Array.isArray(template) || template.length === 0) return undefined;
451
+ const mapped = (levelMap && typeof levelMap[raw] === 'string' && levelMap[raw]!.trim()) ? levelMap[raw]!.trim() : raw;
452
+ return template.map((part) => part.includes('{{level}}') ? part.replace('{{level}}', mapped) : part);
453
+ }
454
+
215
455
  function readSubcommandSessionId(args: string[], subcommands: string[]): string | undefined {
216
456
  const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
217
457
  if (resumeIndex < 0) return undefined;
@@ -255,10 +495,14 @@ function detectExplicitProviderSessionId(
255
495
 
256
496
  const subcommands = resume?.sessionIdFromSubcommand;
257
497
  if (Array.isArray(subcommands) && subcommands.length > 0) {
498
+ const hasResumeSubcommand = args.some((arg) => subcommands.includes(arg));
258
499
  const subcommandSessionId = readSubcommandSessionId(args, subcommands);
259
500
  if (subcommandSessionId) {
260
501
  return { providerSessionId: subcommandSessionId, launchMode: 'resume' };
261
502
  }
503
+ if (hasResumeSubcommand) {
504
+ return { launchMode: 'resume' };
505
+ }
262
506
  }
263
507
 
264
508
  return { launchMode: 'manual' };
@@ -292,6 +536,12 @@ export function resolveCliSessionBinding(
292
536
  launchMode: explicit.launchMode,
293
537
  };
294
538
  }
539
+ if (explicit.launchMode === 'resume') {
540
+ return {
541
+ cliArgs: baseArgs,
542
+ launchMode: 'resume',
543
+ };
544
+ }
295
545
  if (explicit.launchMode === 'manual' && hasArg(baseArgs || [], ['--session-id'])) {
296
546
  return {
297
547
  cliArgs: baseArgs,
@@ -399,6 +649,7 @@ export class DaemonCliManager {
399
649
  cliArgs?: string[],
400
650
  providerSessionId?: string,
401
651
  attachExisting = false,
652
+ initialMeta?: Record<string, unknown>,
402
653
  ): PtyTransportFactory | undefined {
403
654
  return this.deps.createPtyTransportFactory?.({
404
655
  runtimeId,
@@ -407,6 +658,7 @@ export class DaemonCliManager {
407
658
  cliArgs,
408
659
  providerSessionId,
409
660
  attachExisting,
661
+ ...(initialMeta && Object.keys(initialMeta).length ? { initialMeta } : {}),
410
662
  }) || undefined;
411
663
  }
412
664
 
@@ -435,7 +687,9 @@ export class DaemonCliManager {
435
687
  providerSessionId,
436
688
  attachExisting,
437
689
  );
438
- return new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, extraEnv || {}, transportFactory);
690
+ const adapter = new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, extraEnv || {}, transportFactory);
691
+ if (providerSessionId) adapter.updateRuntimeMeta({ providerSessionId });
692
+ return adapter;
439
693
  }
440
694
 
441
695
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
@@ -457,6 +711,7 @@ export class DaemonCliManager {
457
711
  this.deps.removeAgentTracking(key);
458
712
  sessionRegistry?.unregisterByInstanceKey(key);
459
713
  instanceManager?.removeInstance(key);
714
+ unregisterMeshCoordinator(key);
460
715
  LOG.info('CLI', `🧹 Auto-cleaned ${status.status} CLI: ${cliType}`);
461
716
  this.deps.onStatusChange();
462
717
  }
@@ -479,6 +734,16 @@ export class DaemonCliManager {
479
734
  providerSessionId?: string;
480
735
  launchMode?: CliLaunchMode;
481
736
  extraEnv?: Record<string, string>;
737
+ /** BRAIN-ROUTING: post-launch thinking level for runtime-control providers
738
+ * (e.g. hermes reasoning). Passed through to the instance. */
739
+ initialThinkingLevel?: string;
740
+ /**
741
+ * On an attach (attachExisting=true), the real spawn time (ms epoch) of the
742
+ * session-host runtime being restored — a PAST timestamp. Used to restore the
743
+ * native-history session-floor to the runtime's actual birth instead of 0.
744
+ * See the spawnedAtMs computation below. Ignored for fresh launches.
745
+ */
746
+ attachStartedAtMs?: number;
482
747
  onProviderSessionResolved?: (info: {
483
748
  instanceId: string;
484
749
  providerType: string;
@@ -492,6 +757,24 @@ export class DaemonCliManager {
492
757
  const instanceManager = this.deps.getInstanceManager();
493
758
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
494
759
  if (!instanceManager) throw new Error('InstanceManager not available');
760
+
761
+ // Launch-time record meta (mesh node binding) — computed BEFORE the
762
+ // transport factory so the session-host record can be seeded with the
763
+ // binding at create_session time (Fix ②, defense-in-depth for
764
+ // SESSION-ACCUMULATION-LEAK), not only via the post-spawn WTDISPATCH
765
+ // updateRuntimeMeta round-trip below. See CliTransportFactoryParams.initialMeta.
766
+ const launchMeshNodeId = typeof settings?.meshNodeId === 'string' ? settings.meshNodeId.trim() : '';
767
+ const launchMeshNodeFor = typeof settings?.meshNodeFor === 'string' ? settings.meshNodeFor.trim() : '';
768
+ const launchAutoLaunchedForQueueTaskId = typeof settings?.autoLaunchedForQueueTaskId === 'string'
769
+ ? settings.autoLaunchedForQueueTaskId.trim()
770
+ : '';
771
+ const launchRecordMeta: Record<string, unknown> = {
772
+ ...(launchMeshNodeId ? { meshNodeId: launchMeshNodeId } : {}),
773
+ ...(launchMeshNodeFor ? { meshNodeFor: launchMeshNodeFor } : {}),
774
+ ...(settings?.launchedByCoordinator === true ? { launchedByCoordinator: true } : {}),
775
+ ...(launchAutoLaunchedForQueueTaskId ? { autoLaunchedForQueueTaskId: launchAutoLaunchedForQueueTaskId } : {}),
776
+ };
777
+
495
778
  const transportFactory = this.getTransportFactory(
496
779
  key,
497
780
  normalizedType,
@@ -499,6 +782,9 @@ export class DaemonCliManager {
499
782
  cliArgs,
500
783
  options?.providerSessionId,
501
784
  attachExisting,
785
+ // Only seed at create time for fresh launches — an attach restores an
786
+ // existing record whose meta is already stamped; re-seeding could clobber.
787
+ attachExisting ? undefined : launchRecordMeta,
502
788
  );
503
789
  const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, options);
504
790
  try {
@@ -516,6 +802,33 @@ export class DaemonCliManager {
516
802
  transport: 'pty',
517
803
  adapterKey: key,
518
804
  instanceKey: key,
805
+ workspace: resolvedDir,
806
+ // attachExisting === true means we're restoring an already-spawned
807
+ // hosted runtime after a daemon restart, not starting a fresh PTY.
808
+ //
809
+ // NEVER use Date.now() for the attach case: the real spawn time is in
810
+ // the PAST, and pinning the floor to now would push the native-history
811
+ // session-floor cutoff past every existing transcript file, so the
812
+ // agy/hermes/claude reader would return null even though the transcript
813
+ // on disk is fresh (the ANTIGRAVITY-FINAL-MESSAGE-TAIL-GAP regression).
814
+ //
815
+ // But collapsing to 0 for EVERY attach is also wrong: with the mesh
816
+ // coordinator + MAGI replicas all running as hosted runtimes sharing one
817
+ // workspace and attached with attachExisting=true, spawnedAtMs=0 disables
818
+ // the per-session native-history birth-floor for all of them. Without a
819
+ // floor, resolveAntigravityPath takes the floor-less newest-by-mtime
820
+ // branch (ownerConfirmed:false) and a replica's read can claim the
821
+ // coordinator's OWN conversation, which then reads as claimedByOther —
822
+ // regressing the coordinator chat to the pty-parser (user-only) path.
823
+ //
824
+ // So when the session-host record's REAL startedAt (a PAST timestamp) is
825
+ // recoverable, use it: the floor lands at the runtime's actual birth, the
826
+ // transcript is still found, AND each session's floor isolates its own
827
+ // conversation. Fall back to 0 ONLY when startedAt is unrecoverable (the
828
+ // genuine post-restart-unknown case) — that preserves the tail-gap
829
+ // protection. Fresh launches still get Date.now() so prior-session leak
830
+ // protection holds.
831
+ spawnedAtMs: resolveHostedSpawnedAtMs(attachExisting, options?.attachStartedAtMs, Date.now()),
519
832
  });
520
833
  } catch (spawnErr: any) {
521
834
  LOG.error('CLI', `[${cliType}] Spawn failed: ${spawnErr?.message}`);
@@ -524,6 +837,28 @@ export class DaemonCliManager {
524
837
  }
525
838
 
526
839
  this.adapters.set(key, cliInstance.getAdapter());
840
+
841
+ // WTDISPATCH (no_node_binding): a coordinator-launched worker carries its mesh node
842
+ // binding on the CLI-instance settings, but the session-host RECORD meta was never
843
+ // stamped with it — `updateRuntimeSettings` only mutates in-memory runtime settings and
844
+ // `updateRuntimeMeta` was only ever called with providerSessionId. So mesh_cleanup_sessions
845
+ // matched these worker sessions to a node by workspace ALONE
846
+ // (`live_session_matched_by_workspace_only_no_node_binding`), which on a daemon hosting
847
+ // sibling worktree nodes cannot tell two co-located clones apart. Push the launch-time node
848
+ // binding to the record meta so the record is 1:1 bound to its node (the spawned pty exists
849
+ // by now, so updateMeta reaches the session-host store). Best-effort; guarded.
850
+ //
851
+ // With the spec-CLI updateRuntimeMeta fix (SpecCliAdapter now forwards the FULL
852
+ // meta down to the transport, not just providerSessionId), this stamp finally
853
+ // reaches the session-host record for spec-backed providers too — previously it
854
+ // was silently dropped, which is what let orphans accumulate. launchRecordMeta
855
+ // is hoisted above and also seeds the create_session record via initialMeta.
856
+ if (Object.keys(launchRecordMeta).length) {
857
+ try {
858
+ cliInstance.getAdapter().updateRuntimeMeta?.({ ...launchRecordMeta });
859
+ } catch { /* best-effort — record-meta stamp is cleanup hygiene, not on the dispatch path */ }
860
+ }
861
+
527
862
  this.startCliExitMonitor(key, cliType);
528
863
  }
529
864
 
@@ -556,6 +891,24 @@ export class DaemonCliManager {
556
891
 
557
892
  // Create UUID-based key (allows separate instances even for same type+dir)
558
893
  const key = crypto.randomUUID();
894
+
895
+ // (3) Session-anchored mesh routing: when launching a mesh COORDINATOR session
896
+ // (settings.meshCoordinatorFor set), expose this session's OWN runtime id to its MCP
897
+ // server via env. The MCP server is spawned by the CLI as a child and inherits this
898
+ // env, so the MCP layer can stamp ADHDEV_COORDINATOR_SESSION_ID as the originating
899
+ // coordinator on every dispatch (→ MeshContext.coordinatorSessionId → worker
900
+ // meshCoordinatorSessionId → completion targetCoordinatorSessionId → strict route).
901
+ // `key` IS the instance id findLiveCoordinators matches on, so the stamp and the live
902
+ // session agree. Re-applied on every (re)launch, so it always reflects the current id;
903
+ // a stale value only survives if the CLI process outlives a daemon restart, in which
904
+ // case routing falls back to the daemon level (no wedge — see mesh-reconcile-loop).
905
+ {
906
+ const coordinatorMeshId = (options?.settingsOverride as Record<string, unknown> | undefined)?.meshCoordinatorFor;
907
+ if (typeof coordinatorMeshId === 'string' && coordinatorMeshId.trim()) {
908
+ options = { ...options, extraEnv: { ...(options?.extraEnv || {}), ADHDEV_COORDINATOR_SESSION_ID: key } };
909
+ }
910
+ }
911
+
559
912
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
560
913
 
561
914
  // ─── ACP category handle ───
@@ -589,6 +942,7 @@ export class DaemonCliManager {
589
942
  transport: 'acp',
590
943
  adapterKey: key,
591
944
  instanceKey: key,
945
+ workspace: resolvedDir,
592
946
  });
593
947
 
594
948
  // Register ACP entry in adapter map (getStatus queries from acpInstance in real-time)
@@ -631,6 +985,19 @@ export class DaemonCliManager {
631
985
  }
632
986
  }
633
987
 
988
+ // Brain routing thinking axis for ACP: route the standard level through the
989
+ // agent's thought_level config option. Best-effort — throws if the agent declares
990
+ // no thought_level category (see setConfigOption), so we swallow and warn.
991
+ if (options?.initialThinkingLevel) {
992
+ const lvl = options.initialThinkingLevel;
993
+ try {
994
+ await acpInstance.setConfigOption('thought_level', lvl);
995
+ console.log(colorize('green', ` 🧠 Initial thinking level set: ${lvl}`));
996
+ } catch (e: any) {
997
+ LOG.warn('CLI', `[ACP] Initial thinking level set failed (provider may not support thought_level): ${e?.message}`);
998
+ }
999
+ }
1000
+
634
1001
  this.persistRecentActivity({
635
1002
  kind: 'acp',
636
1003
  providerType: normalizedType,
@@ -663,8 +1030,37 @@ export class DaemonCliManager {
663
1030
  console.log(colorize('cyan', ` 📦 Using provider: ${provider.name} (${provider.type})`));
664
1031
  }
665
1032
 
1033
+ // ─── Model axis (MAGI kind-panel): expand initialModel → launch args ───
1034
+ // For a plain CLI provider the model is selected at spawn time via the manifest's
1035
+ // modelLaunchArgs template ('{{model}}' → the requested model). ACP providers took
1036
+ // the setConfigOption path above and never reach here. A provider with no template,
1037
+ // or no requested model, is a no-op — model selection is best-effort and must never
1038
+ // fail a launch. The model args are prepended so a caller's explicit cliArgs (e.g. a
1039
+ // resume flag) still win positionally where order matters.
1040
+ const modelLaunchArgs = expandModelLaunchArgs(provider?.modelLaunchArgs, initialModel);
1041
+ const cliArgsWithModel = modelLaunchArgs
1042
+ ? [...modelLaunchArgs, ...(cliArgs || [])]
1043
+ : cliArgs;
1044
+ if (initialModel && !modelLaunchArgs) {
1045
+ LOG.warn('CLI', `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template — launching without model selection.`);
1046
+ }
1047
+
1048
+ // ─── Thinking axis (brain routing): expand initialThinkingLevel → launch args ───
1049
+ // Parallel to the model axis: a plain CLI provider selects reasoning effort at spawn
1050
+ // via the manifest's thinkingLaunchArgs template ('{{level}}' → the mapped level).
1051
+ // Best-effort; a provider with no template (or no requested level) is a no-op. ACP
1052
+ // providers route thinking through setConfigOption('thought_level') above.
1053
+ const initialThinkingLevel = options?.initialThinkingLevel;
1054
+ const thinkingLaunchArgs = expandThinkingLaunchArgs(provider?.thinkingLaunchArgs, initialThinkingLevel, provider?.thinkingLevelMap);
1055
+ const cliArgsWithBrain = thinkingLaunchArgs
1056
+ ? [...thinkingLaunchArgs, ...(cliArgsWithModel || [])]
1057
+ : cliArgsWithModel;
1058
+ if (initialThinkingLevel && !thinkingLaunchArgs) {
1059
+ LOG.warn('CLI', `[${normalizedType}] initialThinkingLevel='${initialThinkingLevel}' requested but provider declares no thinkingLaunchArgs template — launching without thinking-level selection.`);
1060
+ }
1061
+
666
1062
  // ─── Resolve launch options → provider session binding ───
667
- const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgs, options?.resumeSessionId);
1063
+ const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithBrain, options?.resumeSessionId);
668
1064
  const resolvedCliArgs = sessionBinding.cliArgs;
669
1065
 
670
1066
  // If InstanceManager exists, manage as CliProviderInstance unified
@@ -684,6 +1080,10 @@ export class DaemonCliManager {
684
1080
  providerSessionId: sessionBinding.providerSessionId,
685
1081
  launchMode: sessionBinding.launchMode,
686
1082
  extraEnv: options?.extraEnv,
1083
+ // BRAIN-ROUTING: for a provider with no thinkingLaunchArgs but a
1084
+ // runtime reasoning control (hermes), apply the level post-launch.
1085
+ // The launch-arg providers (claude/codex) already consumed it at spawn.
1086
+ ...(options?.initialThinkingLevel && !provider?.thinkingLaunchArgs ? { initialThinkingLevel: options.initialThinkingLevel } : {}),
687
1087
  onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
688
1088
  this.persistRecentActivity({
689
1089
  kind: 'cli',
@@ -783,6 +1183,7 @@ export class DaemonCliManager {
783
1183
  this.deps.removeAgentTracking(key);
784
1184
  this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
785
1185
  this.deps.getInstanceManager()?.removeInstance(key);
1186
+ unregisterMeshCoordinator(key);
786
1187
  LOG.info('CLI', `🛑 Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
787
1188
  this.deps.onStatusChange();
788
1189
  } else {
@@ -792,6 +1193,7 @@ export class DaemonCliManager {
792
1193
  this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
793
1194
  im.removeInstance(key);
794
1195
  this.deps.removeAgentTracking(key);
1196
+ unregisterMeshCoordinator(key);
795
1197
  LOG.warn('CLI', `🧹 Force-removed orphan entry: ${key}`);
796
1198
  this.deps.onStatusChange();
797
1199
  }
@@ -819,6 +1221,29 @@ export class DaemonCliManager {
819
1221
  const restoredBindings = new Set<string>();
820
1222
  const managerTag = this.deps.hostedRuntimeManagerTag;
821
1223
 
1224
+ // CORDBADGE worker-overbind guard pre-pass: the workspace-scoped coordinator
1225
+ // rebind fallback (below) recovers a coordinator's mark when its runtimeId
1226
+ // changed across restart. But a delegated WORKER session that shares the
1227
+ // coordinator's workspace+cliType ALSO misses the exact by-id lookup, so the
1228
+ // fallback would wrongly stamp it with the lone registered coordinator's mesh
1229
+ // mark (the reported bug: a worker shown with role:coordinator after restart).
1230
+ // Two batch-level signals let the fallback refuse to mark a worker:
1231
+ // - restoredRuntimeIds: every runtimeId in this restore batch. If a
1232
+ // registered coordinator's own sessionId appears here, that coordinator is
1233
+ // being restored under its known id (the exact match binds it), so ANY
1234
+ // other same-workspace session is a worker — not the renamed coordinator.
1235
+ // - workspaceTypeCounts: how many sessions in the batch share a
1236
+ // workspace+cliType. >1 means we cannot tell the coordinator from a worker
1237
+ // even if the coordinator's id changed, so we stay unbound (ambiguous).
1238
+ const restoredRuntimeIds = new Set<string>();
1239
+ const workspaceTypeCounts = new Map<string, number>();
1240
+ for (const r of sessions) {
1241
+ if (!r?.runtimeId || !r?.cliType || !r?.workspace) continue;
1242
+ restoredRuntimeIds.add(r.runtimeId);
1243
+ const key = `${r.workspace}::${r.cliType}`;
1244
+ workspaceTypeCounts.set(key, (workspaceTypeCounts.get(key) || 0) + 1);
1245
+ }
1246
+
822
1247
  for (const record of sessions) {
823
1248
  if (!record?.runtimeId || !record?.cliType || !record?.workspace) continue;
824
1249
  if (!shouldRestoreHostedRuntime(record, managerTag)) {
@@ -852,6 +1277,74 @@ export class DaemonCliManager {
852
1277
  );
853
1278
  continue;
854
1279
  }
1280
+ // Re-establish the launch-time settings a fresh launch applies. startSession
1281
+ // seeds every new instance with { ...providerLoader.getSettings(type), ...override };
1282
+ // passing a bare {} here on restart silently dropped TWO launch settings, so a
1283
+ // restored session diverged from a freshly-launched one:
1284
+ // - autoApprove (a provider/machine setting from getSettings) → a restored
1285
+ // coordinator self-session lost auto-approve and re-prompted on every tool call.
1286
+ // - meshCoordinatorFor (the coordinator launch's settingsOverride) → the restored
1287
+ // session was no longer recognized as this daemon's live CLI coordinator by
1288
+ // findLiveCoordinators (so pending mesh events stopped draining into its PTY) nor
1289
+ // surfaced with the coordinator badge via settings. The persisted coordinator
1290
+ // registry (loaded on boot) is the source of truth to rebuild that mark.
1291
+ // Both restores are provider-agnostic — getSettings is keyed by provider type and the
1292
+ // registry mark is type-independent.
1293
+ const restoredSettings: Record<string, any> = { ...this.providerLoader.getSettings(normalizedType) };
1294
+ // Primary rebind: exact persisted-registry match by runtimeId (stable across
1295
+ // restart, see session-host runtimeId = runtimeRecord.sessionId).
1296
+ let coordinatorEntry = getCoordinatorForSession(record.runtimeId);
1297
+ // CORDBADGE fallback: the by-id match misses when a coordinator's runtime
1298
+ // re-attaches under a different runtimeId than the one it was registered with
1299
+ // (the registry survived, but its key no longer lines up). Without a rebind the
1300
+ // restored session silently loses meshCoordinatorFor → the coordinator badge and
1301
+ // selfIdentification block vanish and pending mesh events stop draining into its
1302
+ // PTY, and the only recovery is a manual coordinator restart. Recover the mark
1303
+ // from the persisted registry scoped to this exact workspace, but ONLY when it is
1304
+ // UNAMBIGUOUS: exactly one registered coordinator for this workspace AND its
1305
+ // cliType matches the restored session's type.
1306
+ //
1307
+ // WORKER-OVERBIND guard: "exactly one registered coordinator" is NOT enough —
1308
+ // a delegated worker session sharing the coordinator's workspace+cliType also
1309
+ // misses the by-id lookup, and the registry holding only the (single) real
1310
+ // coordinator does NOT stop the fallback from projecting that coordinator's
1311
+ // mark onto the worker record. So before adopting the mark we positively rule
1312
+ // the worker out:
1313
+ // (a) coordinatorPresentById — the registered coordinator's own sessionId is
1314
+ // in this restore batch, i.e. it is being restored under its known id and
1315
+ // the exact match already binds it. Then THIS record (which missed) is a
1316
+ // worker, not the renamed coordinator → do not rebind.
1317
+ // (b) siblingCount > 1 — more than one session shares this workspace+cliType,
1318
+ // so even if the coordinator's id changed we cannot tell it from a worker
1319
+ // → stay unbound (ambiguous).
1320
+ // Anything ambiguous stays unbound (we would rather miss a badge than
1321
+ // mis-attribute one).
1322
+ if (!coordinatorEntry?.meshId && record.workspace) {
1323
+ const workspaceCoordinators = listCoordinatorsForWorkspace(record.workspace)
1324
+ .filter(e => e.meshId && (!e.cliType || e.cliType === record.cliType));
1325
+ if (workspaceCoordinators.length === 1) {
1326
+ const candidate = workspaceCoordinators[0];
1327
+ const coordinatorPresentById = !!candidate.sessionId && restoredRuntimeIds.has(candidate.sessionId);
1328
+ const siblingCount = workspaceTypeCounts.get(`${record.workspace}::${record.cliType}`) || 1;
1329
+ if (!coordinatorPresentById && siblingCount === 1) {
1330
+ coordinatorEntry = candidate;
1331
+ LOG.info(
1332
+ 'CLI',
1333
+ `↻ Rebound coordinator mark by workspace for ${record.runtimeKey || record.runtimeId} (mesh ${candidate.meshId} @ ${record.workspace}); registry key did not match runtimeId`
1334
+ );
1335
+ } else {
1336
+ LOG.info(
1337
+ 'CLI',
1338
+ `↷ Skipping workspace coordinator rebind for ${record.runtimeKey || record.runtimeId} (${record.cliType} @ ${record.workspace}): ${coordinatorPresentById
1339
+ ? 'registered coordinator is restoring under its own id — this is a delegated worker'
1340
+ : `ambiguous (${siblingCount} sessions share this workspace+cliType)`}`
1341
+ );
1342
+ }
1343
+ }
1344
+ }
1345
+ if (coordinatorEntry?.meshId) {
1346
+ restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
1347
+ }
855
1348
  try {
856
1349
  await this.registerCliInstance(
857
1350
  record.runtimeId,
@@ -860,11 +1353,17 @@ export class DaemonCliManager {
860
1353
  record.workspace,
861
1354
  record.cliArgs,
862
1355
  resolvedProvider,
863
- {},
1356
+ restoredSettings,
864
1357
  true,
865
1358
  {
866
1359
  providerSessionId: sessionBinding.providerSessionId,
867
1360
  launchMode: 'manual',
1361
+ // Thread the runtime's REAL past spawn time so the attach restores
1362
+ // the per-session native-history birth-floor instead of collapsing
1363
+ // to spawnedAtMs:0 (which disabled the antigravity per-session floor
1364
+ // and let MAGI replicas claim the coordinator's own conversation).
1365
+ // Undefined → registerCliInstance keeps the 0 fallback.
1366
+ attachStartedAtMs: record.startedAtMs,
868
1367
  },
869
1368
  );
870
1369
  restoredBindings.add(bindingKey);
@@ -899,18 +1398,36 @@ export class DaemonCliManager {
899
1398
  const adapter = this.adapters.get(ik);
900
1399
  if (adapter) return { adapter, key: ik };
901
1400
  }
902
- // 1. agentType + dir match
903
- if (opts?.dir) {
1401
+ // 1. agentType + dir match.
1402
+ // FAIL-CLOSED when an explicit instanceKey/targetSessionId was named (step 0) but
1403
+ // did not resolve: the caller pinned a SPECIFIC session, so healing by workspace must
1404
+ // not silently redirect the command into a co-located SIBLING worktree session. The
1405
+ // remote mesh relay (ipcDispatchToRemoteAgent) carries `dir: node.workspace` alongside
1406
+ // targetSessionId for the sessionless-scope case; when a session WAS named, that dir
1407
+ // fallback is the WTDISPATCH-FANOUT (a) leak — a stale/relaunched session_id would
1408
+ // dir-match whatever session lives in that workspace instead of failing. The sessionless
1409
+ // node-scoped path uses findMeshNodeAdapter, not this fallback, so gating dir on
1410
+ // !instanceKey loses no legitimate routing. Mirror step 2's fail-closed rule.
1411
+ if (opts?.dir && !opts?.instanceKey) {
904
1412
  for (const [k, a] of this.adapters) {
905
1413
  if (a.cliType === agentType && a.workingDir === opts.dir) {
906
1414
  return { adapter: a, key: k };
907
1415
  }
908
1416
  }
909
1417
  }
910
- // 2. Fuzzy match (returns first of multiple sessions — may be inaccurate)
911
- for (const [k, a] of this.adapters) {
912
- if (a.cliType === agentType) {
913
- return { adapter: a, key: k };
1418
+ // 2. Fuzzy match (returns first of multiple sessions — may be inaccurate).
1419
+ // FAIL-CLOSED: only when NO explicit instanceKey/targetSessionId was requested.
1420
+ // When a specific session WAS named (step 0) but is not hosted on this daemon,
1421
+ // falling back to the first same-cliType adapter silently redirects the command
1422
+ // into an UNRELATED session — e.g. a relayed/misrouted mesh send_chat lands in the
1423
+ // coordinator's own CLI session, echoing the dispatched task body back to the
1424
+ // coordinator (TASKECHO self-inject). Returning null instead makes the caller
1425
+ // surface an explicit "not running" error rather than mis-delivering the message.
1426
+ if (!opts?.instanceKey) {
1427
+ for (const [k, a] of this.adapters) {
1428
+ if (a.cliType === agentType) {
1429
+ return { adapter: a, key: k };
1430
+ }
914
1431
  }
915
1432
  }
916
1433
  return null;
@@ -925,6 +1442,40 @@ export class DaemonCliManager {
925
1442
  return adapter ? { adapter, key: ik } : null;
926
1443
  }
927
1444
 
1445
+ /**
1446
+ * WTCLAIM (B): resolve the adapter for a mesh dispatch that named a node
1447
+ * (meshContext.nodeId) but carried no explicit session. Matches by the
1448
+ * instance's bound mesh node id (settings.meshNodeId, falling back to the
1449
+ * sticky meshLastNodeId) first, then by the node workspace (workingDir).
1450
+ *
1451
+ * Unlike findAdapter's step-2 fuzzy fallback, this NEVER degrades to a
1452
+ * provider-only first-match: on a daemon hosting BOTH a base node and a
1453
+ * cloned worktree node (same daemonId), that fuzzy match could land a
1454
+ * worktree-targeted task on the base session. Returns null when no session
1455
+ * is bound to this node so the caller fails closed.
1456
+ */
1457
+ private findMeshNodeAdapter(agentType: string, nodeId: string, dir?: string): { adapter: CliAdapter; key: string } | null {
1458
+ const instanceManager = this.deps.getInstanceManager();
1459
+ const targetDir = normalizeDirForCompare(dir);
1460
+ let workspaceMatch: { adapter: CliAdapter; key: string } | null = null;
1461
+ for (const [k, a] of this.adapters) {
1462
+ if (a.cliType !== agentType) continue;
1463
+ const settings = (instanceManager?.getInstance(k) as any)?.getState?.()?.settings as Record<string, unknown> | undefined;
1464
+ const boundNodeId = (typeof settings?.meshNodeId === 'string' && settings.meshNodeId.trim())
1465
+ ? settings.meshNodeId.trim()
1466
+ : (typeof settings?.meshLastNodeId === 'string' ? settings.meshLastNodeId.trim() : '');
1467
+ // Exact node binding wins immediately (most precise).
1468
+ if (boundNodeId && boundNodeId === nodeId) return { adapter: a, key: k };
1469
+ // Workspace identity is the secondary signal for a session not (yet)
1470
+ // stamped with a node id — a base node and a worktree clone always have
1471
+ // distinct workspaces, so this still separates them.
1472
+ if (!workspaceMatch && targetDir && normalizeDirForCompare(a.workingDir) === targetDir) {
1473
+ workspaceMatch = { adapter: a, key: k };
1474
+ }
1475
+ }
1476
+ return workspaceMatch;
1477
+ }
1478
+
928
1479
  // ─── CLI command handling ────────────────────────────
929
1480
 
930
1481
  async handleCliCommand(cmd: string, args: any): Promise<CommandResult | null> {
@@ -955,6 +1506,8 @@ export class DaemonCliManager {
955
1506
  const launchSource = resolved.source;
956
1507
  if (!cliType) throw new Error('cliType required');
957
1508
 
1509
+ const providerType = this.providerLoader.resolveAlias(cliType);
1510
+ const provLookup = this.providerLoader.getMeta(providerType) as ProviderModule | undefined;
958
1511
  const settingsOverride = args?.settings && typeof args.settings === 'object' ? args.settings : undefined;
959
1512
  const delegatedLaunch = settingsOverride?.launchedByCoordinator === true
960
1513
  ? buildCoordinatorDelegatedCliLaunchOptions({
@@ -962,8 +1515,28 @@ export class DaemonCliManager {
962
1515
  workspace: dir,
963
1516
  cliArgs: args?.cliArgs,
964
1517
  env: args?.env,
1518
+ isolation: provLookup?.meshCoordinator?.delegatedWorkerIsolation,
965
1519
  })
966
1520
  : null;
1521
+ // Untrusted-provider gate: an external source that ships JS
1522
+ // hooks needs explicit user confirmation before its first
1523
+ // launch. Dashboards add `confirmExternalUntrusted: true` to
1524
+ // the launch args after showing the trust modal. Without
1525
+ // that ack we refuse to spawn and tell the caller why.
1526
+ const provMeta = provLookup as any;
1527
+ const provTrust = provMeta?._sourceTrust;
1528
+ if (provTrust === 'external-untrusted' && args?.confirmExternalUntrusted !== true) {
1529
+ return {
1530
+ success: false,
1531
+ error: 'untrusted_external_provider',
1532
+ provider: {
1533
+ type: provLookup?.type ?? cliType,
1534
+ sourceName: provMeta?._sourceName ?? null,
1535
+ trust: provTrust,
1536
+ },
1537
+ hint: 'Resend launch_cli with confirmExternalUntrusted=true after the user explicitly approves running JavaScript from this 3rd-party source.',
1538
+ };
1539
+ }
967
1540
  const started = await this.startSession(
968
1541
  cliType,
969
1542
  dir,
@@ -973,6 +1546,7 @@ export class DaemonCliManager {
973
1546
  resumeSessionId: args?.resumeSessionId,
974
1547
  settingsOverride,
975
1548
  extraEnv: delegatedLaunch ? delegatedLaunch.env : args?.env,
1549
+ ...(typeof args?.initialThinkingLevel === 'string' && args.initialThinkingLevel.trim() ? { initialThinkingLevel: args.initialThinkingLevel.trim() } : {}),
976
1550
  },
977
1551
  );
978
1552
 
@@ -1030,6 +1604,45 @@ export class DaemonCliManager {
1030
1604
  this.deps.onStatusChange();
1031
1605
  return { success: true, id: found.key, mode };
1032
1606
  }
1607
+ case 'record_provider_pty': {
1608
+ const cliType = args?.type || args?.cliType;
1609
+ if (!cliType) {
1610
+ return { success: false, error: '`type` (provider type) is required', code: 'MISSING_TYPE' };
1611
+ }
1612
+ const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId : '';
1613
+ const dir = args?.dir || '';
1614
+ const found = (targetSessionId ? this.findAdapterBySessionId(targetSessionId) : null)
1615
+ || this.findAdapter(cliType, { instanceKey: targetSessionId, dir });
1616
+ if (!found) {
1617
+ return {
1618
+ success: false,
1619
+ error: `No running ${cliType} session. Launch one first (adhdev launch ${cliType}) or pass --target-session-id.`,
1620
+ code: 'NO_RUNNING_SESSION',
1621
+ };
1622
+ }
1623
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
1624
+ if (!(instance instanceof CliProviderInstance)) {
1625
+ return { success: false, error: 'CLI instance not available', code: 'CLI_INSTANCE_NOT_FOUND' };
1626
+ }
1627
+ const adapter = instance.getAdapter();
1628
+ if (!adapter || typeof (adapter as any).getAccumulatedRawBuffer !== 'function') {
1629
+ return { success: false, error: 'Adapter does not expose PTY buffer', code: 'ADAPTER_NOT_RECORDABLE' };
1630
+ }
1631
+ const buffer = (adapter as any).getAccumulatedRawBuffer() as { text: string; droppedChars: number };
1632
+ const maxBytes = Number(args?.maxBytes) > 0 ? Number(args.maxBytes) : 262144;
1633
+ const truncated = buffer.text.length > maxBytes;
1634
+ const ptyBytes = truncated ? buffer.text.slice(-maxBytes) : buffer.text;
1635
+ return {
1636
+ success: true,
1637
+ cliType,
1638
+ sessionId: found.key,
1639
+ ptyBytes,
1640
+ bytes: ptyBytes.length,
1641
+ truncated,
1642
+ droppedChars: buffer.droppedChars,
1643
+ capturedAt: Date.now(),
1644
+ };
1645
+ }
1033
1646
  case 'restart_session': {
1034
1647
  const cliType = args?.cliType || args?.agentType || args?.ideType;
1035
1648
  const cfg = loadConfig();
@@ -1065,14 +1678,68 @@ export class DaemonCliManager {
1065
1678
  const action = args?.action;
1066
1679
  if (!agentType || !action) throw new Error('agentType and action required');
1067
1680
 
1068
- const found = this.findAdapter(agentType, {
1069
- dir: args?.dir,
1070
- instanceKey: args?.targetSessionId,
1071
- });
1681
+ // WTCLAIM (B): a mesh dispatch that named a node (meshContext.nodeId)
1682
+ // but resolved no explicit session must be scoped to THAT node's
1683
+ // session — never routed by findAdapter's provider-only fuzzy fallback,
1684
+ // which on a daemon hosting both a base node and a cloned worktree node
1685
+ // (same daemonId) could land a worktree task on the base session. Fail
1686
+ // closed when no session is bound to the node so the coordinator
1687
+ // launches/retries instead of mis-landing the work.
1688
+ const meshScopeNodeId = (() => {
1689
+ const mc = (args as any)?.meshContext;
1690
+ return mc && typeof mc === 'object' && typeof mc.nodeId === 'string' ? mc.nodeId.trim() : '';
1691
+ })();
1692
+ let found: { adapter: CliAdapter; key: string } | null;
1693
+ if (meshScopeNodeId && !args?.targetSessionId) {
1694
+ found = this.findMeshNodeAdapter(agentType, meshScopeNodeId, args?.dir);
1695
+ if (!found) {
1696
+ throw new Error(`No mesh worker session bound to node '${meshScopeNodeId}' for agent '${agentType}' on this daemon; refusing provider-only fuzzy match to avoid cross-node dispatch`);
1697
+ }
1698
+ } else {
1699
+ found = this.findAdapter(agentType, {
1700
+ dir: args?.dir,
1701
+ instanceKey: args?.targetSessionId,
1702
+ });
1703
+ }
1072
1704
  if (!found) throw new Error(`CLI agent not running: ${agentType}`);
1073
1705
  const { adapter, key } = found;
1074
1706
 
1075
1707
  if (action === 'send_chat') {
1708
+ let currentStatus = getEffectiveAgentSendStatus(adapter);
1709
+ if (currentStatus === 'starting' && await waitForZeroMessageStartingLaunch(adapter)) {
1710
+ currentStatus = 'idle';
1711
+ } else if (currentStatus === 'starting') {
1712
+ currentStatus = getEffectiveAgentSendStatus(adapter);
1713
+ }
1714
+ // Stamp mesh direct-dispatch assignment on the target
1715
+ // instance BEFORE sending the prompt so the completion
1716
+ // event has a routing marker by the time it fires.
1717
+ // mesh_send_task --direct ships meshContext for plain CLI
1718
+ // sessions that were never launched as mesh delegates.
1719
+ const meshContext = (args as any)?.meshContext;
1720
+ if (meshContext && typeof meshContext === 'object' && typeof meshContext.meshId === 'string' && meshContext.meshId) {
1721
+ const targetInstanceId = key;
1722
+ let stampResult: { stamped: boolean; reason?: string } | undefined;
1723
+ try {
1724
+ stampResult = this.deps.getInstanceManager()?.attachMeshAssignmentToInstance(targetInstanceId, {
1725
+ meshId: meshContext.meshId,
1726
+ ...(typeof meshContext.nodeId === 'string' && meshContext.nodeId ? { nodeId: meshContext.nodeId } : {}),
1727
+ ...(typeof meshContext.taskId === 'string' && meshContext.taskId ? { taskId: meshContext.taskId } : {}),
1728
+ // REDRIVE-DUP: carry the dispatch nonce onto the worker session so
1729
+ // its generating_started event echoes it back for the coordinator's
1730
+ // stale-nonce guard.
1731
+ ...(typeof meshContext.dispatchNonce === 'number' ? { dispatchNonce: meshContext.dispatchNonce } : {}),
1732
+ ...(typeof meshContext.coordinatorDaemonId === 'string' && meshContext.coordinatorDaemonId ? { coordinatorDaemonId: meshContext.coordinatorDaemonId } : {}),
1733
+ });
1734
+ } catch { /* best-effort — stamping is a routing aid, not a hard requirement */ }
1735
+ // DOUBLE-DISPATCH stamp guard: the instance manager refused this stamp because
1736
+ // the SAME task is already running on another live session on this daemon.
1737
+ // Sending the prompt anyway would double-execute the task — fail closed so the
1738
+ // coordinator does not duplicate the work onto a second session.
1739
+ if (stampResult && stampResult.stamped === false && stampResult.reason === 'task_already_stamped_on_live_instance') {
1740
+ throw new Error(`Refusing duplicate mesh dispatch: task ${meshContext.taskId} is already being worked by a live session on this daemon`);
1741
+ }
1742
+ }
1076
1743
  const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
1077
1744
  const provider = this.providerLoader.resolve(agentType) || this.providerLoader.getMeta(agentType);
1078
1745
  if (provider?.category === 'acp') {
@@ -1082,8 +1749,38 @@ export class DaemonCliManager {
1082
1749
  }
1083
1750
  const message = input.textFallback;
1084
1751
  if (!message) throw new Error('message required for send_chat');
1085
- await adapter.sendMessage(message);
1086
- return { success: true, status: 'generating' };
1752
+ // ARCH-REFACTOR R1: thread the dispatched task's id into the turn so the
1753
+ // worker's completion event is bound to THIS task (per-turn identity),
1754
+ // not the last-write-wins session scalar. Carried for both local and
1755
+ // remote (P2P-echoed meshContext) dispatch; absent for plain ad-hoc chat.
1756
+ const meshTaskId = (meshContext && typeof meshContext === 'object'
1757
+ && typeof (meshContext as any).taskId === 'string' && (meshContext as any).taskId.trim())
1758
+ ? (meshContext as any).taskId as string
1759
+ : undefined;
1760
+ const forceSend = args?.force === true || args?.forceSend === true;
1761
+ // Preserve the exact prior call shape when there is no taskId (plain
1762
+ // ad-hoc chat / non-mesh dispatch); only thread the per-turn taskId when
1763
+ // present, so existing non-mesh callers and their contracts are unchanged.
1764
+ if (forceSend && typeof (adapter as any).forceSendMessage === 'function') {
1765
+ if (meshTaskId) await (adapter as any).forceSendMessage(message, meshTaskId);
1766
+ else await (adapter as any).forceSendMessage(message);
1767
+ } else if (forceSend) {
1768
+ await adapter.sendMessage(message, meshTaskId ? { force: true, meshTaskId } : { force: true });
1769
+ } else if (meshTaskId) {
1770
+ await adapter.sendMessage(message, { meshTaskId });
1771
+ } else {
1772
+ await adapter.sendMessage(message);
1773
+ }
1774
+ const targetInstance = this.deps.getInstanceManager()?.getInstance(key) as
1775
+ | { recordAcknowledgedUserInput?: (input: unknown) => void }
1776
+ | undefined;
1777
+ targetInstance?.recordAcknowledgedUserInput?.(input);
1778
+ return {
1779
+ success: true,
1780
+ status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : 'generating',
1781
+ ...(BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: 'agent_runtime_busy' } : {}),
1782
+ ...(forceSend ? { forceSent: true, queued: false } : {}),
1783
+ };
1087
1784
  } else if (action === 'clear_history') {
1088
1785
  if (typeof adapter.clearHistory === 'function') adapter.clearHistory();
1089
1786
  return { success: true, cleared: true };