@adhdev/daemon-core 0.9.82-rc.36 → 0.9.82-rc.361

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 (335) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +8 -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 +55 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +198 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +116 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +53 -0
  14. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  15. package/dist/cli-adapters/resolve-executable.d.ts +14 -0
  16. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  17. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  18. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  19. package/dist/commands/cli-manager.d.ts +15 -1
  20. package/dist/commands/handler.d.ts +125 -0
  21. package/dist/commands/low-family/index.d.ts +3 -0
  22. package/dist/commands/low-family/refine-config.d.ts +2 -0
  23. package/dist/commands/low-family/session-host.d.ts +2 -0
  24. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  25. package/dist/commands/low-family/types.d.ts +16 -0
  26. package/dist/commands/mesh-coordinator.d.ts +85 -1
  27. package/dist/commands/router.d.ts +336 -2
  28. package/dist/commands/upgrade-helper.d.ts +41 -1
  29. package/dist/config/chat-history.d.ts +9 -0
  30. package/dist/config/config.d.ts +5 -0
  31. package/dist/config/mesh-config.d.ts +77 -1
  32. package/dist/detection/ide-detector.d.ts +13 -0
  33. package/dist/detection/win32-ide-version.d.ts +37 -0
  34. package/dist/git/change-impact-config.d.ts +159 -0
  35. package/dist/git/git-commands.d.ts +11 -1
  36. package/dist/git/git-diff.d.ts +6 -0
  37. package/dist/git/git-executor.d.ts +11 -0
  38. package/dist/git/git-status.d.ts +23 -0
  39. package/dist/git/git-types.d.ts +2 -50
  40. package/dist/git/index.d.ts +2 -0
  41. package/dist/index.d.ts +54 -13
  42. package/dist/index.js +41337 -14723
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +44100 -17614
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/installer.d.ts +1 -4
  47. package/dist/ipc/local-ipc-server.d.ts +91 -0
  48. package/dist/launch.d.ts +1 -1
  49. package/dist/logging/async-batch-writer.d.ts +10 -0
  50. package/dist/logging/log-redactor.d.ts +24 -0
  51. package/dist/logging/log-tail-reader.d.ts +46 -0
  52. package/dist/logging/logger.d.ts +1 -1
  53. package/dist/mesh/contracts.d.ts +164 -0
  54. package/dist/mesh/coordinator-prompt.d.ts +36 -0
  55. package/dist/mesh/coordinator-registry.d.ts +59 -0
  56. package/dist/mesh/mesh-active-work.d.ts +174 -0
  57. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  58. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  59. package/dist/mesh/mesh-events-coordinator.d.ts +170 -0
  60. package/dist/mesh/mesh-events-pending.d.ts +55 -0
  61. package/dist/mesh/mesh-events-stale.d.ts +40 -0
  62. package/dist/mesh/mesh-events-utils.d.ts +60 -0
  63. package/dist/mesh/mesh-events.d.ts +6 -49
  64. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  65. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  66. package/dist/mesh/mesh-init.d.ts +86 -0
  67. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
  68. package/dist/mesh/mesh-ledger.d.ts +77 -1
  69. package/dist/mesh/mesh-missions.d.ts +164 -0
  70. package/dist/mesh/mesh-reconcile-loop.d.ts +7 -0
  71. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  72. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  73. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  74. package/dist/mesh/mesh-routing.d.ts +70 -0
  75. package/dist/mesh/mesh-runtime-store.d.ts +429 -0
  76. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  77. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  78. package/dist/mesh/mesh-work-queue.d.ts +246 -5
  79. package/dist/mesh/preview-freshness.d.ts +18 -0
  80. package/dist/mesh/refine-config.d.ts +216 -0
  81. package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
  82. package/dist/providers/acp-provider-instance.d.ts +5 -0
  83. package/dist/providers/approval-utils.d.ts +20 -0
  84. package/dist/providers/chat-message-normalization.d.ts +12 -0
  85. package/dist/providers/cli-provider-instance.d.ts +106 -3
  86. package/dist/providers/contracts.d.ts +139 -6
  87. package/dist/providers/external-sources.d.ts +71 -0
  88. package/dist/providers/manual-attendance.d.ts +63 -0
  89. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
  90. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  91. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  92. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  93. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  94. package/dist/providers/native-history/index.d.ts +13 -0
  95. package/dist/providers/provider-instance-manager.d.ts +14 -0
  96. package/dist/providers/provider-instance.d.ts +23 -1
  97. package/dist/providers/provider-loader.d.ts +26 -4
  98. package/dist/providers/provider-trust.d.ts +31 -0
  99. package/dist/providers/read-chat-contract.d.ts +29 -0
  100. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  101. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  102. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  103. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  104. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  105. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  106. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  107. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  108. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  109. package/dist/providers/sdk/v1/index.d.ts +30 -0
  110. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  111. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  112. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  113. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  114. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  115. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  116. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  117. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  118. package/dist/providers/spec/adapter.d.ts +91 -0
  119. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  120. package/dist/providers/spec/evaluator.d.ts +45 -0
  121. package/dist/providers/spec/fsm-driver.d.ts +368 -0
  122. package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
  123. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  124. package/dist/providers/spec/fsm-types.d.ts +174 -0
  125. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  126. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  127. package/dist/providers/spec/route.d.ts +4 -0
  128. package/dist/providers/spec/types.d.ts +222 -0
  129. package/dist/providers/status-monitor.d.ts +7 -7
  130. package/dist/providers/transcript-v2.d.ts +176 -0
  131. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  132. package/dist/providers/working-dir.d.ts +17 -0
  133. package/dist/repo-mesh-types.d.ts +295 -13
  134. package/dist/sessions/registry.d.ts +6 -0
  135. package/dist/shared-types-extra.d.ts +2 -4
  136. package/dist/shared-types.d.ts +59 -2
  137. package/dist/status/normalize.d.ts +1 -1
  138. package/dist/status/normalize.js +1 -0
  139. package/dist/status/normalize.js.map +1 -1
  140. package/dist/status/normalize.mjs +1 -0
  141. package/dist/status/normalize.mjs.map +1 -1
  142. package/dist/status/reporter.d.ts +2 -0
  143. package/dist/status/snapshot.d.ts +26 -0
  144. package/dist/system/load-better-sqlite3.d.ts +21 -0
  145. package/dist/types.d.ts +5 -0
  146. package/package.json +7 -3
  147. package/src/agent-stream/poller.ts +2 -3
  148. package/src/agent-stream/provider-adapter.ts +1 -1
  149. package/src/boot/daemon-lifecycle.ts +55 -12
  150. package/src/boot/process-hardening.ts +89 -0
  151. package/src/build-info.ts +73 -0
  152. package/src/chat/source-machine.ts +534 -0
  153. package/src/chat/source-resolver.ts +0 -0
  154. package/src/chat/subscription-updates.ts +20 -1
  155. package/src/cli-adapter-types.d.ts +1 -0
  156. package/src/cli-adapter-types.ts +56 -2
  157. package/src/cli-adapters/cli-script-runner.ts +421 -0
  158. package/src/cli-adapters/cli-state-engine.ts +1215 -0
  159. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  160. package/src/cli-adapters/provider-cli-adapter.ts +774 -1141
  161. package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
  162. package/src/cli-adapters/provider-cli-parse.ts +13 -0
  163. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  164. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  165. package/src/cli-adapters/provider-cli-shared.ts +100 -11
  166. package/src/cli-adapters/pty-transport.ts +2 -1
  167. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  168. package/src/cli-adapters/resolve-executable.ts +90 -0
  169. package/src/cli-adapters/session-host-transport.ts +2 -1
  170. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +53 -29
  171. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  172. package/src/cli-adapters/terminal-screen.ts +16 -81
  173. package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
  174. package/src/commands/chat-commands.ts +1823 -62
  175. package/src/commands/cli-manager.ts +405 -23
  176. package/src/commands/handler.ts +841 -2
  177. package/src/commands/low-family/index.ts +23 -0
  178. package/src/commands/low-family/refine-config.ts +106 -0
  179. package/src/commands/low-family/session-host.ts +274 -0
  180. package/src/commands/low-family/spec-providerdev.ts +217 -0
  181. package/src/commands/low-family/types.ts +19 -0
  182. package/src/commands/mesh-coordinator.ts +332 -122
  183. package/src/commands/router.ts +7195 -1423
  184. package/src/commands/stream-commands.ts +8 -0
  185. package/src/commands/upgrade-helper.ts +310 -45
  186. package/src/config/chat-history.ts +483 -24
  187. package/src/config/config.ts +12 -0
  188. package/src/config/mesh-config.ts +388 -6
  189. package/src/config/recent-activity.ts +8 -2
  190. package/src/daemon/dev-auto-implement.ts +3 -2
  191. package/src/daemon/dev-cli-debug.ts +10 -1
  192. package/src/detection/cli-detector.ts +28 -9
  193. package/src/detection/ide-detector.ts +55 -16
  194. package/src/detection/win32-ide-version.ts +106 -0
  195. package/src/git/change-impact-config.ts +354 -0
  196. package/src/git/git-commands.ts +55 -14
  197. package/src/git/git-diff.ts +81 -11
  198. package/src/git/git-executor.ts +12 -0
  199. package/src/git/git-status.ts +574 -43
  200. package/src/git/git-types.ts +14 -62
  201. package/src/git/git-worktree.ts +8 -1
  202. package/src/git/index.ts +16 -0
  203. package/src/index.ts +156 -12
  204. package/src/installer.d.ts +1 -1
  205. package/src/installer.ts +8 -6
  206. package/src/ipc/local-ipc-server.ts +278 -0
  207. package/src/launch.d.ts +1 -1
  208. package/src/launch.ts +37 -28
  209. package/src/logging/async-batch-writer.ts +55 -0
  210. package/src/logging/command-log.ts +7 -5
  211. package/src/logging/log-redactor.ts +100 -0
  212. package/src/logging/log-tail-reader.ts +220 -0
  213. package/src/logging/logger.ts +14 -7
  214. package/src/mesh/contracts.ts +338 -0
  215. package/src/mesh/coordinator-prompt.ts +234 -31
  216. package/src/mesh/coordinator-registry.ts +121 -0
  217. package/src/mesh/mesh-active-work.ts +667 -0
  218. package/src/mesh/mesh-delivery-policy.ts +315 -0
  219. package/src/mesh/mesh-event-trace.ts +67 -0
  220. package/src/mesh/mesh-events-coordinator.ts +2572 -0
  221. package/src/mesh/mesh-events-pending.ts +599 -0
  222. package/src/mesh/mesh-events-stale.ts +309 -0
  223. package/src/mesh/mesh-events-utils.ts +361 -0
  224. package/src/mesh/mesh-events.ts +30 -1035
  225. package/src/mesh/mesh-fast-forward.ts +839 -0
  226. package/src/mesh/mesh-host-ownership.ts +73 -0
  227. package/src/mesh/mesh-init.ts +260 -0
  228. package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
  229. package/src/mesh/mesh-ledger.ts +591 -102
  230. package/src/mesh/mesh-missions.ts +322 -0
  231. package/src/mesh/mesh-reconcile-loop.ts +1096 -0
  232. package/src/mesh/mesh-refine-batch.ts +197 -0
  233. package/src/mesh/mesh-refine-status.ts +231 -0
  234. package/src/mesh/mesh-review-inbox.ts +307 -0
  235. package/src/mesh/mesh-routing.ts +291 -0
  236. package/src/mesh/mesh-runtime-store.ts +1697 -0
  237. package/src/mesh/mesh-task-stats.ts +161 -0
  238. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  239. package/src/mesh/mesh-work-queue.ts +997 -141
  240. package/src/mesh/preview-freshness.ts +118 -0
  241. package/src/mesh/refine-config.ts +423 -0
  242. package/src/mesh/worktree-bootstrap-config.ts +331 -0
  243. package/src/providers/acp-provider-instance.ts +43 -10
  244. package/src/providers/approval-utils.d.ts +5 -0
  245. package/src/providers/approval-utils.ts +57 -5
  246. package/src/providers/chat-message-normalization.ts +45 -5
  247. package/src/providers/cli-provider-instance.ts +1267 -101
  248. package/src/providers/contracts.d.ts +55 -0
  249. package/src/providers/contracts.ts +150 -6
  250. package/src/providers/extension-provider-instance.ts +12 -7
  251. package/src/providers/external-sources.ts +218 -0
  252. package/src/providers/ide-provider-instance.ts +35 -12
  253. package/src/providers/manual-attendance.ts +85 -0
  254. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  255. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  256. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  257. package/src/providers/native-history/dispatcher.ts +340 -0
  258. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  259. package/src/providers/native-history/index.ts +30 -0
  260. package/src/providers/provider-instance-manager.ts +30 -0
  261. package/src/providers/provider-instance.ts +19 -1
  262. package/src/providers/provider-loader.ts +670 -50
  263. package/src/providers/provider-schema.ts +87 -14
  264. package/src/providers/provider-trust.ts +114 -0
  265. package/src/providers/read-chat-contract.ts +76 -16
  266. package/src/providers/sdk/README.md +49 -0
  267. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  268. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  269. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  270. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  271. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  272. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  273. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  274. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  275. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  276. package/src/providers/sdk/v1/index.ts +152 -0
  277. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  278. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  279. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  280. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
  281. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  282. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  283. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  284. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  285. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  286. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  287. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  288. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  289. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  290. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  291. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  292. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  293. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  294. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  295. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  296. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  297. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  298. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  299. package/src/providers/sdk/v1/validators/index.ts +19 -0
  300. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  301. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  302. package/src/providers/spec/adapter.ts +235 -0
  303. package/src/providers/spec/cli-adapter.ts +1051 -0
  304. package/src/providers/spec/evaluator.ts +407 -0
  305. package/src/providers/spec/fsm-driver.ts +1251 -0
  306. package/src/providers/spec/fsm-evaluator.ts +272 -0
  307. package/src/providers/spec/fsm-loader.ts +120 -0
  308. package/src/providers/spec/fsm-types.ts +273 -0
  309. package/src/providers/spec/native-history-executor.ts +1136 -0
  310. package/src/providers/spec/pre-launch-trust.ts +104 -0
  311. package/src/providers/spec/route.ts +51 -0
  312. package/src/providers/spec/types.ts +262 -0
  313. package/src/providers/status-monitor.d.ts +7 -7
  314. package/src/providers/status-monitor.ts +37 -22
  315. package/src/providers/transcript-v2.ts +567 -0
  316. package/src/providers/types/interactive-prompt.ts +536 -0
  317. package/src/providers/version-archive.ts +64 -24
  318. package/src/providers/working-dir.ts +23 -0
  319. package/src/repo-mesh-types.ts +378 -14
  320. package/src/sessions/registry.ts +6 -0
  321. package/src/shared-types-extra.ts +2 -4
  322. package/src/shared-types.d.ts +8 -0
  323. package/src/shared-types.ts +64 -1
  324. package/src/status/builders.ts +26 -6
  325. package/src/status/normalize.ts +2 -0
  326. package/src/status/reporter.ts +19 -1
  327. package/src/status/snapshot.ts +95 -26
  328. package/src/system/host-memory.ts +29 -12
  329. package/src/system/load-better-sqlite3.ts +68 -0
  330. package/src/types.ts +5 -0
  331. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  332. package/dist/mesh/mesh-sync.d.ts +0 -53
  333. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  334. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  335. package/src/mesh/mesh-sync.ts +0 -111
@@ -18,13 +18,14 @@ 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 { unregisterMeshCoordinator, getCoordinatorForSession } from '../mesh/coordinator-registry.js';
21
22
  import { upsertSavedProviderSession } from '../config/saved-sessions.js';
22
23
  import { buildLegacyModelModeSummaryMetadata, normalizeProviderSummaryMetadata } from '../providers/summary-metadata.js';
23
24
  import { CliProviderInstance } from '../providers/cli-provider-instance.js';
24
25
  import { AcpProviderInstance } from '../providers/acp-provider-instance.js';
25
26
  import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
26
27
  import { ProviderLoader } from '../providers/provider-loader.js';
27
- import { normalizeInputEnvelope, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
28
+ import { normalizeInputEnvelope, type MeshCoordinatorDelegatedWorkerIsolation, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
28
29
  import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
29
30
  import type { CliAdapter } from '../cli-adapter-types.js';
30
31
  import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
@@ -80,6 +81,126 @@ export interface CliManagerDeps {
80
81
 
81
82
  type CommandResult = { success: boolean;[key: string]: unknown };
82
83
 
84
+ const BUSY_AGENT_STATUSES = new Set(['generating', 'running', 'streaming', 'starting', 'busy', 'waiting', 'waiting_approval', 'no_progress', 'long_generating']);
85
+ const ZERO_MESSAGE_STARTING_SEND_WAIT_MS = 2_000;
86
+
87
+ function normalizeAgentStatus(value: unknown): string {
88
+ return typeof value === 'string' ? value.trim().toLowerCase() : '';
89
+ }
90
+
91
+ function hasNonEmptyModalButtons(activeModal: unknown): boolean {
92
+ const buttons = (activeModal as any)?.buttons;
93
+ return Array.isArray(buttons) && buttons.some((button) => String(button || '').trim().length > 0);
94
+ }
95
+
96
+ function hasAdapterPendingResponse(adapter: any): boolean {
97
+ if (adapter?.isWaitingForResponse === true) return true;
98
+ if (adapter?.currentTurnScope) return true;
99
+ try {
100
+ if (typeof adapter?.isProcessing === 'function' && adapter.isProcessing()) return true;
101
+ } catch { /* defensive: send guard should not fail on diagnostics */ }
102
+ try {
103
+ const partial = typeof adapter?.getPartialResponse === 'function' ? adapter.getPartialResponse() : '';
104
+ if (typeof partial === 'string' && partial.trim()) return true;
105
+ } catch { /* defensive: missing partial means no pending evidence */ }
106
+ return false;
107
+ }
108
+
109
+ function countMessages(value: unknown): number {
110
+ return Array.isArray(value) ? value.length : 0;
111
+ }
112
+
113
+ function hasFinalAssistantMessage(value: unknown): boolean {
114
+ const messages = Array.isArray(value) ? value : [];
115
+ const last = messages[messages.length - 1] as any;
116
+ if (!last || last.role !== 'assistant') return false;
117
+ if (last.bubbleState === 'streaming') return false;
118
+ if (last.meta?.streaming === true) return false;
119
+ return typeof last.content === 'string' && last.content.trim().length > 0;
120
+ }
121
+
122
+ function hasZeroMessageStartingLaunch(adapter: any): boolean {
123
+ const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
124
+ const parsedStatus = typeof adapter?.getScriptParsedStatus === 'function'
125
+ ? adapter.getScriptParsedStatus()
126
+ : {};
127
+ const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
128
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
129
+ if (adapterRawStatus !== 'starting') return false;
130
+ if (parsedRawStatus && parsedRawStatus !== 'starting' && parsedRawStatus !== 'generating') return false;
131
+ if (hasNonEmptyModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
132
+ if (countMessages(adapterStatus?.messages) > 0 || countMessages(parsedStatus?.messages) > 0) return false;
133
+ return !hasAdapterPendingResponse(adapter);
134
+ }
135
+
136
+ function hasCompletedStartingLaunch(adapter: any): boolean {
137
+ const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
138
+ const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
139
+ if (adapterRawStatus !== 'starting') return false;
140
+ if (hasAdapterPendingResponse(adapter)) return false;
141
+
142
+ const parsedStatus = typeof adapter?.getScriptParsedStatus === 'function'
143
+ ? adapter.getScriptParsedStatus()
144
+ : {};
145
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
146
+ if (parsedRawStatus !== 'idle') return false;
147
+ if (hasNonEmptyModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
148
+ return hasFinalAssistantMessage(parsedStatus?.messages);
149
+ }
150
+
151
+ /**
152
+ * WTCLAIM (B): compare two workspace paths for node scoping. Normalizes separator
153
+ * style, trailing slashes, and case (Windows paths are case-insensitive; the
154
+ * coordinator-supplied node.workspace and the adapter's launch workingDir can
155
+ * differ only in those) so a base node and a worktree clone are still told apart
156
+ * by their distinct workspace roots.
157
+ */
158
+ function normalizeDirForCompare(dir?: string): string {
159
+ if (typeof dir !== 'string') return '';
160
+ return dir.trim().replace(/[\\/]+/g, '/').replace(/\/+$/, '').toLowerCase();
161
+ }
162
+
163
+ function shouldSuppressStaleParsedBusyStatus(adapterStatus: string, parsedStatus: any, adapter: any): boolean {
164
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
165
+ if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
166
+ if (adapterStatus !== 'idle') return false;
167
+ if (hasNonEmptyModalButtons(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
168
+ return !hasAdapterPendingResponse(adapter);
169
+ }
170
+
171
+ function getEffectiveAgentSendStatus(adapter: any): string {
172
+ const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
173
+ if (adapterStatus === 'starting' && hasCompletedStartingLaunch(adapter)) return 'idle';
174
+ if (adapterStatus && adapterStatus !== 'idle') return adapterStatus;
175
+ if (adapterStatus !== 'idle') return adapterStatus;
176
+
177
+ if (typeof adapter?.getScriptParsedStatus !== 'function') return adapterStatus;
178
+ try {
179
+ const parsedStatus = adapter.getScriptParsedStatus();
180
+ const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
181
+ if (BUSY_AGENT_STATUSES.has(parsedRawStatus) && !shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter)) {
182
+ return parsedRawStatus;
183
+ }
184
+ } catch {
185
+ return adapterStatus;
186
+ }
187
+ return adapterStatus;
188
+ }
189
+
190
+ async function waitForZeroMessageStartingLaunch(adapter: any): Promise<boolean> {
191
+ try {
192
+ if (!hasZeroMessageStartingLaunch(adapter)) return false;
193
+ } catch {
194
+ return false;
195
+ }
196
+ await new Promise(resolve => setTimeout(resolve, ZERO_MESSAGE_STARTING_SEND_WAIT_MS));
197
+ try {
198
+ return hasZeroMessageStartingLaunch(adapter);
199
+ } catch {
200
+ return false;
201
+ }
202
+ }
203
+
83
204
  export interface CliTransportFactoryParams {
84
205
  runtimeId: string;
85
206
  providerType: string;
@@ -138,18 +259,19 @@ type CliStartOptions = {
138
259
  extraEnv?: Record<string, string>;
139
260
  };
140
261
 
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
- };
262
+ const DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS = [
263
+ 'ADHDEV_INLINE_MESH',
264
+ 'ADHDEV_MCP_TRANSPORT',
265
+ 'ADHDEV_MESH_ID',
266
+ 'HERMES_EPHEMERAL_SYSTEM_PROMPT',
267
+ ] as const;
147
268
 
148
269
  export interface CoordinatorDelegatedCliLaunchOptionsInput {
149
270
  cliType: string;
150
271
  workspace: string;
151
272
  cliArgs?: string[];
152
273
  env?: Record<string, string>;
274
+ isolation?: MeshCoordinatorDelegatedWorkerIsolation;
153
275
  }
154
276
 
155
277
  export interface CoordinatorDelegatedCliLaunchOptions {
@@ -161,6 +283,21 @@ function hasCliArg(args: string[], flag: string): boolean {
161
283
  return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
162
284
  }
163
285
 
286
+ function hasConfigOverride(args: string[], key: string): boolean {
287
+ for (let index = 0; index < args.length; index += 1) {
288
+ const arg = args[index];
289
+ const next = args[index + 1];
290
+ if ((arg === '-c' || arg === '--config') && typeof next === 'string') {
291
+ if (next === key || next.startsWith(`${key}=`) || next.startsWith(`${key}.`)) return true;
292
+ }
293
+ if (arg.startsWith('--config=')) {
294
+ const value = arg.slice('--config='.length);
295
+ if (value === key || value.startsWith(`${key}=`) || value.startsWith(`${key}.`)) return true;
296
+ }
297
+ }
298
+ return false;
299
+ }
300
+
164
301
  function ensureEmptyDelegatedMcpConfig(workspace: string): string {
165
302
  const baseDir = path.join(os.tmpdir(), 'adhdev-delegated-agent-empty-mcp');
166
303
  mkdirSync(baseDir, { recursive: true });
@@ -173,12 +310,31 @@ function ensureEmptyDelegatedMcpConfig(workspace: string): string {
173
310
  export function buildCoordinatorDelegatedCliLaunchOptions(
174
311
  input: CoordinatorDelegatedCliLaunchOptionsInput,
175
312
  ): CoordinatorDelegatedCliLaunchOptions {
176
- const cliType = String(input.cliType || '').trim();
177
313
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
178
- const env: Record<string, string> = { ...(input.env || {}), ...COORDINATOR_DELEGATED_ENV_UNSETS };
314
+ const env: Record<string, string> = { ...(input.env || {}) };
315
+ const envUnsets = new Set<string>(DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS);
316
+ for (const key of input.isolation?.env?.unset || []) {
317
+ if (typeof key === 'string' && key.trim()) envUnsets.add(key.trim());
318
+ }
319
+ for (const key of envUnsets) env[key] = '';
179
320
 
180
- if (cliType === 'claude-cli' && !hasCliArg(cliArgs, '--mcp-config')) {
181
- cliArgs.unshift('--mcp-config', ensureEmptyDelegatedMcpConfig(input.workspace));
321
+ for (const rule of input.isolation?.args || []) {
322
+ if (!rule || typeof rule !== 'object') continue;
323
+ if (rule.mode === 'empty_mcp_config') {
324
+ if (rule.flag && !hasCliArg(cliArgs, rule.flag)) {
325
+ cliArgs.unshift(rule.flag, ensureEmptyDelegatedMcpConfig(input.workspace));
326
+ }
327
+ if (rule.strictFlag && !hasCliArg(cliArgs, rule.strictFlag)) {
328
+ cliArgs.unshift(rule.strictFlag);
329
+ }
330
+ continue;
331
+ }
332
+ if (rule.mode === 'config_override') {
333
+ const key = String(rule.dedupeKey || rule.key || '').trim();
334
+ const flag = String(rule.flag || '').trim();
335
+ if (!key || !flag || hasConfigOverride(cliArgs, key)) continue;
336
+ cliArgs.unshift(flag, `${rule.key}=${rule.value}`);
337
+ }
182
338
  }
183
339
 
184
340
  return { cliArgs, env };
@@ -255,10 +411,14 @@ function detectExplicitProviderSessionId(
255
411
 
256
412
  const subcommands = resume?.sessionIdFromSubcommand;
257
413
  if (Array.isArray(subcommands) && subcommands.length > 0) {
414
+ const hasResumeSubcommand = args.some((arg) => subcommands.includes(arg));
258
415
  const subcommandSessionId = readSubcommandSessionId(args, subcommands);
259
416
  if (subcommandSessionId) {
260
417
  return { providerSessionId: subcommandSessionId, launchMode: 'resume' };
261
418
  }
419
+ if (hasResumeSubcommand) {
420
+ return { launchMode: 'resume' };
421
+ }
262
422
  }
263
423
 
264
424
  return { launchMode: 'manual' };
@@ -292,6 +452,12 @@ export function resolveCliSessionBinding(
292
452
  launchMode: explicit.launchMode,
293
453
  };
294
454
  }
455
+ if (explicit.launchMode === 'resume') {
456
+ return {
457
+ cliArgs: baseArgs,
458
+ launchMode: 'resume',
459
+ };
460
+ }
295
461
  if (explicit.launchMode === 'manual' && hasArg(baseArgs || [], ['--session-id'])) {
296
462
  return {
297
463
  cliArgs: baseArgs,
@@ -435,7 +601,9 @@ export class DaemonCliManager {
435
601
  providerSessionId,
436
602
  attachExisting,
437
603
  );
438
- return new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, extraEnv || {}, transportFactory);
604
+ const adapter = new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, extraEnv || {}, transportFactory);
605
+ if (providerSessionId) adapter.updateRuntimeMeta({ providerSessionId });
606
+ return adapter;
439
607
  }
440
608
 
441
609
  throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
@@ -457,6 +625,7 @@ export class DaemonCliManager {
457
625
  this.deps.removeAgentTracking(key);
458
626
  sessionRegistry?.unregisterByInstanceKey(key);
459
627
  instanceManager?.removeInstance(key);
628
+ unregisterMeshCoordinator(key);
460
629
  LOG.info('CLI', `🧹 Auto-cleaned ${status.status} CLI: ${cliType}`);
461
630
  this.deps.onStatusChange();
462
631
  }
@@ -516,6 +685,18 @@ export class DaemonCliManager {
516
685
  transport: 'pty',
517
686
  adapterKey: key,
518
687
  instanceKey: key,
688
+ workspace: resolvedDir,
689
+ // attachExisting === true means we're restoring an already-spawned
690
+ // hosted runtime after a daemon restart, not starting a fresh PTY.
691
+ // The real spawn time is in the past and we don't have it on the
692
+ // restored descriptor; pinning spawnedAtMs to Date.now() in that
693
+ // case would push the native-history session-floor cutoff past
694
+ // every existing transcript file, so the agy/hermes/claude reader
695
+ // would return null even though the transcript on disk is fresh.
696
+ // 0 disables the floor for this session — recent_window_ms in the
697
+ // spec still bounds how far back we look. Fresh launches still
698
+ // get a proper floor so prior-session leak protection holds.
699
+ spawnedAtMs: attachExisting ? 0 : Date.now(),
519
700
  });
520
701
  } catch (spawnErr: any) {
521
702
  LOG.error('CLI', `[${cliType}] Spawn failed: ${spawnErr?.message}`);
@@ -556,6 +737,24 @@ export class DaemonCliManager {
556
737
 
557
738
  // Create UUID-based key (allows separate instances even for same type+dir)
558
739
  const key = crypto.randomUUID();
740
+
741
+ // (3) Session-anchored mesh routing: when launching a mesh COORDINATOR session
742
+ // (settings.meshCoordinatorFor set), expose this session's OWN runtime id to its MCP
743
+ // server via env. The MCP server is spawned by the CLI as a child and inherits this
744
+ // env, so the MCP layer can stamp ADHDEV_COORDINATOR_SESSION_ID as the originating
745
+ // coordinator on every dispatch (→ MeshContext.coordinatorSessionId → worker
746
+ // meshCoordinatorSessionId → completion targetCoordinatorSessionId → strict route).
747
+ // `key` IS the instance id findLiveCoordinators matches on, so the stamp and the live
748
+ // session agree. Re-applied on every (re)launch, so it always reflects the current id;
749
+ // a stale value only survives if the CLI process outlives a daemon restart, in which
750
+ // case routing falls back to the daemon level (no wedge — see mesh-reconcile-loop).
751
+ {
752
+ const coordinatorMeshId = (options?.settingsOverride as Record<string, unknown> | undefined)?.meshCoordinatorFor;
753
+ if (typeof coordinatorMeshId === 'string' && coordinatorMeshId.trim()) {
754
+ options = { ...options, extraEnv: { ...(options?.extraEnv || {}), ADHDEV_COORDINATOR_SESSION_ID: key } };
755
+ }
756
+ }
757
+
559
758
  const sessionRegistry = this.deps.getSessionRegistry?.() || null;
560
759
 
561
760
  // ─── ACP category handle ───
@@ -589,6 +788,7 @@ export class DaemonCliManager {
589
788
  transport: 'acp',
590
789
  adapterKey: key,
591
790
  instanceKey: key,
791
+ workspace: resolvedDir,
592
792
  });
593
793
 
594
794
  // Register ACP entry in adapter map (getStatus queries from acpInstance in real-time)
@@ -783,6 +983,7 @@ export class DaemonCliManager {
783
983
  this.deps.removeAgentTracking(key);
784
984
  this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
785
985
  this.deps.getInstanceManager()?.removeInstance(key);
986
+ unregisterMeshCoordinator(key);
786
987
  LOG.info('CLI', `🛑 Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
787
988
  this.deps.onStatusChange();
788
989
  } else {
@@ -792,6 +993,7 @@ export class DaemonCliManager {
792
993
  this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
793
994
  im.removeInstance(key);
794
995
  this.deps.removeAgentTracking(key);
996
+ unregisterMeshCoordinator(key);
795
997
  LOG.warn('CLI', `🧹 Force-removed orphan entry: ${key}`);
796
998
  this.deps.onStatusChange();
797
999
  }
@@ -852,6 +1054,24 @@ export class DaemonCliManager {
852
1054
  );
853
1055
  continue;
854
1056
  }
1057
+ // Re-establish the launch-time settings a fresh launch applies. startSession
1058
+ // seeds every new instance with { ...providerLoader.getSettings(type), ...override };
1059
+ // passing a bare {} here on restart silently dropped TWO launch settings, so a
1060
+ // restored session diverged from a freshly-launched one:
1061
+ // - autoApprove (a provider/machine setting from getSettings) → a restored
1062
+ // coordinator self-session lost auto-approve and re-prompted on every tool call.
1063
+ // - meshCoordinatorFor (the coordinator launch's settingsOverride) → the restored
1064
+ // session was no longer recognized as this daemon's live CLI coordinator by
1065
+ // findLiveCoordinators (so pending mesh events stopped draining into its PTY) nor
1066
+ // surfaced with the coordinator badge via settings. The persisted coordinator
1067
+ // registry (loaded on boot) is the source of truth to rebuild that mark.
1068
+ // Both restores are provider-agnostic — getSettings is keyed by provider type and the
1069
+ // registry mark is type-independent.
1070
+ const restoredSettings: Record<string, any> = { ...this.providerLoader.getSettings(normalizedType) };
1071
+ const coordinatorEntry = getCoordinatorForSession(record.runtimeId);
1072
+ if (coordinatorEntry?.meshId) {
1073
+ restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
1074
+ }
855
1075
  try {
856
1076
  await this.registerCliInstance(
857
1077
  record.runtimeId,
@@ -860,7 +1080,7 @@ export class DaemonCliManager {
860
1080
  record.workspace,
861
1081
  record.cliArgs,
862
1082
  resolvedProvider,
863
- {},
1083
+ restoredSettings,
864
1084
  true,
865
1085
  {
866
1086
  providerSessionId: sessionBinding.providerSessionId,
@@ -907,10 +1127,19 @@ export class DaemonCliManager {
907
1127
  }
908
1128
  }
909
1129
  }
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 };
1130
+ // 2. Fuzzy match (returns first of multiple sessions — may be inaccurate).
1131
+ // FAIL-CLOSED: only when NO explicit instanceKey/targetSessionId was requested.
1132
+ // When a specific session WAS named (step 0) but is not hosted on this daemon,
1133
+ // falling back to the first same-cliType adapter silently redirects the command
1134
+ // into an UNRELATED session — e.g. a relayed/misrouted mesh send_chat lands in the
1135
+ // coordinator's own CLI session, echoing the dispatched task body back to the
1136
+ // coordinator (TASKECHO self-inject). Returning null instead makes the caller
1137
+ // surface an explicit "not running" error rather than mis-delivering the message.
1138
+ if (!opts?.instanceKey) {
1139
+ for (const [k, a] of this.adapters) {
1140
+ if (a.cliType === agentType) {
1141
+ return { adapter: a, key: k };
1142
+ }
914
1143
  }
915
1144
  }
916
1145
  return null;
@@ -925,6 +1154,40 @@ export class DaemonCliManager {
925
1154
  return adapter ? { adapter, key: ik } : null;
926
1155
  }
927
1156
 
1157
+ /**
1158
+ * WTCLAIM (B): resolve the adapter for a mesh dispatch that named a node
1159
+ * (meshContext.nodeId) but carried no explicit session. Matches by the
1160
+ * instance's bound mesh node id (settings.meshNodeId, falling back to the
1161
+ * sticky meshLastNodeId) first, then by the node workspace (workingDir).
1162
+ *
1163
+ * Unlike findAdapter's step-2 fuzzy fallback, this NEVER degrades to a
1164
+ * provider-only first-match: on a daemon hosting BOTH a base node and a
1165
+ * cloned worktree node (same daemonId), that fuzzy match could land a
1166
+ * worktree-targeted task on the base session. Returns null when no session
1167
+ * is bound to this node so the caller fails closed.
1168
+ */
1169
+ private findMeshNodeAdapter(agentType: string, nodeId: string, dir?: string): { adapter: CliAdapter; key: string } | null {
1170
+ const instanceManager = this.deps.getInstanceManager();
1171
+ const targetDir = normalizeDirForCompare(dir);
1172
+ let workspaceMatch: { adapter: CliAdapter; key: string } | null = null;
1173
+ for (const [k, a] of this.adapters) {
1174
+ if (a.cliType !== agentType) continue;
1175
+ const settings = (instanceManager?.getInstance(k) as any)?.getState?.()?.settings as Record<string, unknown> | undefined;
1176
+ const boundNodeId = (typeof settings?.meshNodeId === 'string' && settings.meshNodeId.trim())
1177
+ ? settings.meshNodeId.trim()
1178
+ : (typeof settings?.meshLastNodeId === 'string' ? settings.meshLastNodeId.trim() : '');
1179
+ // Exact node binding wins immediately (most precise).
1180
+ if (boundNodeId && boundNodeId === nodeId) return { adapter: a, key: k };
1181
+ // Workspace identity is the secondary signal for a session not (yet)
1182
+ // stamped with a node id — a base node and a worktree clone always have
1183
+ // distinct workspaces, so this still separates them.
1184
+ if (!workspaceMatch && targetDir && normalizeDirForCompare(a.workingDir) === targetDir) {
1185
+ workspaceMatch = { adapter: a, key: k };
1186
+ }
1187
+ }
1188
+ return workspaceMatch;
1189
+ }
1190
+
928
1191
  // ─── CLI command handling ────────────────────────────
929
1192
 
930
1193
  async handleCliCommand(cmd: string, args: any): Promise<CommandResult | null> {
@@ -955,6 +1218,8 @@ export class DaemonCliManager {
955
1218
  const launchSource = resolved.source;
956
1219
  if (!cliType) throw new Error('cliType required');
957
1220
 
1221
+ const providerType = this.providerLoader.resolveAlias(cliType);
1222
+ const provLookup = this.providerLoader.getMeta(providerType) as ProviderModule | undefined;
958
1223
  const settingsOverride = args?.settings && typeof args.settings === 'object' ? args.settings : undefined;
959
1224
  const delegatedLaunch = settingsOverride?.launchedByCoordinator === true
960
1225
  ? buildCoordinatorDelegatedCliLaunchOptions({
@@ -962,8 +1227,28 @@ export class DaemonCliManager {
962
1227
  workspace: dir,
963
1228
  cliArgs: args?.cliArgs,
964
1229
  env: args?.env,
1230
+ isolation: provLookup?.meshCoordinator?.delegatedWorkerIsolation,
965
1231
  })
966
1232
  : null;
1233
+ // Untrusted-provider gate: an external source that ships JS
1234
+ // hooks needs explicit user confirmation before its first
1235
+ // launch. Dashboards add `confirmExternalUntrusted: true` to
1236
+ // the launch args after showing the trust modal. Without
1237
+ // that ack we refuse to spawn and tell the caller why.
1238
+ const provMeta = provLookup as any;
1239
+ const provTrust = provMeta?._sourceTrust;
1240
+ if (provTrust === 'external-untrusted' && args?.confirmExternalUntrusted !== true) {
1241
+ return {
1242
+ success: false,
1243
+ error: 'untrusted_external_provider',
1244
+ provider: {
1245
+ type: provLookup?.type ?? cliType,
1246
+ sourceName: provMeta?._sourceName ?? null,
1247
+ trust: provTrust,
1248
+ },
1249
+ hint: 'Resend launch_cli with confirmExternalUntrusted=true after the user explicitly approves running JavaScript from this 3rd-party source.',
1250
+ };
1251
+ }
967
1252
  const started = await this.startSession(
968
1253
  cliType,
969
1254
  dir,
@@ -1030,6 +1315,45 @@ export class DaemonCliManager {
1030
1315
  this.deps.onStatusChange();
1031
1316
  return { success: true, id: found.key, mode };
1032
1317
  }
1318
+ case 'record_provider_pty': {
1319
+ const cliType = args?.type || args?.cliType;
1320
+ if (!cliType) {
1321
+ return { success: false, error: '`type` (provider type) is required', code: 'MISSING_TYPE' };
1322
+ }
1323
+ const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId : '';
1324
+ const dir = args?.dir || '';
1325
+ const found = (targetSessionId ? this.findAdapterBySessionId(targetSessionId) : null)
1326
+ || this.findAdapter(cliType, { instanceKey: targetSessionId, dir });
1327
+ if (!found) {
1328
+ return {
1329
+ success: false,
1330
+ error: `No running ${cliType} session. Launch one first (adhdev launch ${cliType}) or pass --target-session-id.`,
1331
+ code: 'NO_RUNNING_SESSION',
1332
+ };
1333
+ }
1334
+ const instance = this.deps.getInstanceManager()?.getInstance(found.key);
1335
+ if (!(instance instanceof CliProviderInstance)) {
1336
+ return { success: false, error: 'CLI instance not available', code: 'CLI_INSTANCE_NOT_FOUND' };
1337
+ }
1338
+ const adapter = instance.getAdapter();
1339
+ if (!adapter || typeof (adapter as any).getAccumulatedRawBuffer !== 'function') {
1340
+ return { success: false, error: 'Adapter does not expose PTY buffer', code: 'ADAPTER_NOT_RECORDABLE' };
1341
+ }
1342
+ const buffer = (adapter as any).getAccumulatedRawBuffer() as { text: string; droppedChars: number };
1343
+ const maxBytes = Number(args?.maxBytes) > 0 ? Number(args.maxBytes) : 262144;
1344
+ const truncated = buffer.text.length > maxBytes;
1345
+ const ptyBytes = truncated ? buffer.text.slice(-maxBytes) : buffer.text;
1346
+ return {
1347
+ success: true,
1348
+ cliType,
1349
+ sessionId: found.key,
1350
+ ptyBytes,
1351
+ bytes: ptyBytes.length,
1352
+ truncated,
1353
+ droppedChars: buffer.droppedChars,
1354
+ capturedAt: Date.now(),
1355
+ };
1356
+ }
1033
1357
  case 'restart_session': {
1034
1358
  const cliType = args?.cliType || args?.agentType || args?.ideType;
1035
1359
  const cfg = loadConfig();
@@ -1065,14 +1389,56 @@ export class DaemonCliManager {
1065
1389
  const action = args?.action;
1066
1390
  if (!agentType || !action) throw new Error('agentType and action required');
1067
1391
 
1068
- const found = this.findAdapter(agentType, {
1069
- dir: args?.dir,
1070
- instanceKey: args?.targetSessionId,
1071
- });
1392
+ // WTCLAIM (B): a mesh dispatch that named a node (meshContext.nodeId)
1393
+ // but resolved no explicit session must be scoped to THAT node's
1394
+ // session — never routed by findAdapter's provider-only fuzzy fallback,
1395
+ // which on a daemon hosting both a base node and a cloned worktree node
1396
+ // (same daemonId) could land a worktree task on the base session. Fail
1397
+ // closed when no session is bound to the node so the coordinator
1398
+ // launches/retries instead of mis-landing the work.
1399
+ const meshScopeNodeId = (() => {
1400
+ const mc = (args as any)?.meshContext;
1401
+ return mc && typeof mc === 'object' && typeof mc.nodeId === 'string' ? mc.nodeId.trim() : '';
1402
+ })();
1403
+ let found: { adapter: CliAdapter; key: string } | null;
1404
+ if (meshScopeNodeId && !args?.targetSessionId) {
1405
+ found = this.findMeshNodeAdapter(agentType, meshScopeNodeId, args?.dir);
1406
+ if (!found) {
1407
+ 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`);
1408
+ }
1409
+ } else {
1410
+ found = this.findAdapter(agentType, {
1411
+ dir: args?.dir,
1412
+ instanceKey: args?.targetSessionId,
1413
+ });
1414
+ }
1072
1415
  if (!found) throw new Error(`CLI agent not running: ${agentType}`);
1073
1416
  const { adapter, key } = found;
1074
1417
 
1075
1418
  if (action === 'send_chat') {
1419
+ let currentStatus = getEffectiveAgentSendStatus(adapter);
1420
+ if (currentStatus === 'starting' && await waitForZeroMessageStartingLaunch(adapter)) {
1421
+ currentStatus = 'idle';
1422
+ } else if (currentStatus === 'starting') {
1423
+ currentStatus = getEffectiveAgentSendStatus(adapter);
1424
+ }
1425
+ // Stamp mesh direct-dispatch assignment on the target
1426
+ // instance BEFORE sending the prompt so the completion
1427
+ // event has a routing marker by the time it fires.
1428
+ // mesh_send_task --direct ships meshContext for plain CLI
1429
+ // sessions that were never launched as mesh delegates.
1430
+ const meshContext = (args as any)?.meshContext;
1431
+ if (meshContext && typeof meshContext === 'object' && typeof meshContext.meshId === 'string' && meshContext.meshId) {
1432
+ const targetInstanceId = key;
1433
+ try {
1434
+ this.deps.getInstanceManager()?.attachMeshAssignmentToInstance(targetInstanceId, {
1435
+ meshId: meshContext.meshId,
1436
+ ...(typeof meshContext.nodeId === 'string' && meshContext.nodeId ? { nodeId: meshContext.nodeId } : {}),
1437
+ ...(typeof meshContext.taskId === 'string' && meshContext.taskId ? { taskId: meshContext.taskId } : {}),
1438
+ ...(typeof meshContext.coordinatorDaemonId === 'string' && meshContext.coordinatorDaemonId ? { coordinatorDaemonId: meshContext.coordinatorDaemonId } : {}),
1439
+ });
1440
+ } catch { /* best-effort */ }
1441
+ }
1076
1442
  const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
1077
1443
  const provider = this.providerLoader.resolve(agentType) || this.providerLoader.getMeta(agentType);
1078
1444
  if (provider?.category === 'acp') {
@@ -1082,8 +1448,24 @@ export class DaemonCliManager {
1082
1448
  }
1083
1449
  const message = input.textFallback;
1084
1450
  if (!message) throw new Error('message required for send_chat');
1085
- await adapter.sendMessage(message);
1086
- return { success: true, status: 'generating' };
1451
+ const forceSend = args?.force === true || args?.forceSend === true;
1452
+ if (forceSend && typeof (adapter as any).forceSendMessage === 'function') {
1453
+ await (adapter as any).forceSendMessage(message);
1454
+ } else if (forceSend) {
1455
+ await adapter.sendMessage(message, { force: true });
1456
+ } else {
1457
+ await adapter.sendMessage(message);
1458
+ }
1459
+ const targetInstance = this.deps.getInstanceManager()?.getInstance(key) as
1460
+ | { recordAcknowledgedUserInput?: (input: unknown) => void }
1461
+ | undefined;
1462
+ targetInstance?.recordAcknowledgedUserInput?.(input);
1463
+ return {
1464
+ success: true,
1465
+ status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : 'generating',
1466
+ ...(BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: 'agent_runtime_busy' } : {}),
1467
+ ...(forceSend ? { forceSent: true, queued: false } : {}),
1468
+ };
1087
1469
  } else if (action === 'clear_history') {
1088
1470
  if (typeof adapter.clearHistory === 'function') adapter.clearHistory();
1089
1471
  return { success: true, cleared: true };