@adhdev/daemon-core 0.9.82-rc.45 → 0.9.82-rc.450

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 (427) 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 +200 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +126 -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 +7 -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 +25 -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 +29 -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.d.ts +279 -2
  56. package/dist/commands/upgrade-helper.d.ts +41 -1
  57. package/dist/config/chat-history.d.ts +9 -0
  58. package/dist/config/config.d.ts +5 -0
  59. package/dist/config/mesh-config.d.ts +129 -1
  60. package/dist/config/mesh-json-config.d.ts +199 -0
  61. package/dist/config/repo-settings.d.ts +77 -0
  62. package/dist/daemon/dev-server.d.ts +0 -2
  63. package/dist/detection/ide-detector.d.ts +13 -0
  64. package/dist/detection/win32-ide-version.d.ts +37 -0
  65. package/dist/git/change-impact-config.d.ts +159 -0
  66. package/dist/git/git-commands.d.ts +12 -1
  67. package/dist/git/git-diff.d.ts +6 -0
  68. package/dist/git/git-executor.d.ts +11 -0
  69. package/dist/git/git-status.d.ts +57 -0
  70. package/dist/git/git-types.d.ts +2 -50
  71. package/dist/git/git-worktree.d.ts +71 -1
  72. package/dist/git/index.d.ts +3 -1
  73. package/dist/index.d.ts +66 -14
  74. package/dist/index.js +48475 -17084
  75. package/dist/index.js.map +1 -1
  76. package/dist/index.mjs +49521 -18300
  77. package/dist/index.mjs.map +1 -1
  78. package/dist/installer.d.ts +1 -4
  79. package/dist/ipc/local-ipc-server.d.ts +91 -0
  80. package/dist/launch.d.ts +1 -1
  81. package/dist/logging/async-batch-writer.d.ts +10 -0
  82. package/dist/logging/log-redactor.d.ts +24 -0
  83. package/dist/logging/log-tail-reader.d.ts +81 -0
  84. package/dist/logging/logger.d.ts +1 -1
  85. package/dist/mesh/contracts.d.ts +164 -0
  86. package/dist/mesh/coordinator-prompt.d.ts +89 -0
  87. package/dist/mesh/coordinator-registry.d.ts +59 -0
  88. package/dist/mesh/mesh-active-work.d.ts +174 -0
  89. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  90. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  91. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  92. package/dist/mesh/mesh-event-classify.d.ts +5 -0
  93. package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
  94. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  95. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  96. package/dist/mesh/mesh-events-pending.d.ts +69 -0
  97. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  98. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  99. package/dist/mesh/mesh-events.d.ts +6 -49
  100. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  101. package/dist/mesh/mesh-host-ownership.d.ts +29 -0
  102. package/dist/mesh/mesh-init.d.ts +128 -0
  103. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  104. package/dist/mesh/mesh-ledger.d.ts +115 -1
  105. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  106. package/dist/mesh/mesh-missions.d.ts +189 -0
  107. package/dist/mesh/mesh-node-identity.d.ts +306 -0
  108. package/dist/mesh/mesh-queue-assignment.d.ts +113 -0
  109. package/dist/mesh/mesh-reconcile-loop.d.ts +79 -0
  110. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  111. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  112. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  113. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  114. package/dist/mesh/mesh-routing.d.ts +70 -0
  115. package/dist/mesh/mesh-runtime-store.d.ts +450 -0
  116. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  117. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  118. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  119. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  120. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  121. package/dist/mesh/mesh-work-queue.d.ts +300 -5
  122. package/dist/mesh/preview-freshness.d.ts +18 -0
  123. package/dist/mesh/refine-config.d.ts +216 -0
  124. package/dist/mesh/worktree-bootstrap-config.d.ts +145 -0
  125. package/dist/providers/acp-provider-instance.d.ts +5 -0
  126. package/dist/providers/approval-utils.d.ts +20 -0
  127. package/dist/providers/chat-message-normalization.d.ts +32 -1
  128. package/dist/providers/cli-provider-instance.d.ts +254 -3
  129. package/dist/providers/contracts.d.ts +149 -6
  130. package/dist/providers/external-sources.d.ts +71 -0
  131. package/dist/providers/manual-attendance.d.ts +63 -0
  132. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +126 -0
  133. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  134. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  135. package/dist/providers/native-history/constants.d.ts +12 -0
  136. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  137. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  138. package/dist/providers/native-history/index.d.ts +13 -0
  139. package/dist/providers/provider-instance-manager.d.ts +29 -0
  140. package/dist/providers/provider-instance.d.ts +23 -1
  141. package/dist/providers/provider-loader.d.ts +26 -4
  142. package/dist/providers/provider-trust.d.ts +31 -0
  143. package/dist/providers/read-chat-contract.d.ts +29 -0
  144. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  145. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  146. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  147. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  148. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  149. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  150. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  151. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  152. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  153. package/dist/providers/sdk/v1/index.d.ts +30 -0
  154. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  155. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  156. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  157. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  158. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  159. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  160. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  161. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  162. package/dist/providers/spec/adapter.d.ts +98 -0
  163. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  164. package/dist/providers/spec/evaluator.d.ts +45 -0
  165. package/dist/providers/spec/fsm-driver.d.ts +444 -0
  166. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  167. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  168. package/dist/providers/spec/fsm-types.d.ts +202 -0
  169. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  170. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  171. package/dist/providers/spec/route.d.ts +4 -0
  172. package/dist/providers/spec/types.d.ts +222 -0
  173. package/dist/providers/status-monitor.d.ts +7 -7
  174. package/dist/providers/transcript-v2.d.ts +176 -0
  175. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  176. package/dist/providers/working-dir.d.ts +17 -0
  177. package/dist/repo-mesh-types.d.ts +519 -13
  178. package/dist/runtime-defaults.d.ts +2 -0
  179. package/dist/session-host/managed-host.d.ts +64 -0
  180. package/dist/sessions/registry.d.ts +6 -0
  181. package/dist/shared-types-extra.d.ts +2 -4
  182. package/dist/shared-types.d.ts +59 -2
  183. package/dist/status/normalize.d.ts +1 -1
  184. package/dist/status/normalize.js +1 -0
  185. package/dist/status/normalize.js.map +1 -1
  186. package/dist/status/normalize.mjs +1 -0
  187. package/dist/status/normalize.mjs.map +1 -1
  188. package/dist/status/reporter.d.ts +2 -0
  189. package/dist/status/snapshot.d.ts +26 -0
  190. package/dist/system/hash.d.ts +8 -0
  191. package/dist/system/load-better-sqlite3.d.ts +21 -0
  192. package/dist/types.d.ts +5 -0
  193. package/package.json +7 -3
  194. package/src/agent-stream/poller.ts +2 -3
  195. package/src/agent-stream/provider-adapter.ts +1 -1
  196. package/src/boot/daemon-lifecycle.ts +63 -12
  197. package/src/boot/process-hardening.ts +89 -0
  198. package/src/build-info.ts +73 -0
  199. package/src/chat/source-machine.ts +534 -0
  200. package/src/chat/source-resolver.ts +0 -0
  201. package/src/chat/subscription-updates.ts +20 -1
  202. package/src/cli-adapter-types.d.ts +3 -1
  203. package/src/cli-adapter-types.ts +68 -2
  204. package/src/cli-adapters/cli-script-runner.ts +421 -0
  205. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  206. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  207. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  208. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  209. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  210. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  211. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  212. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  213. package/src/cli-adapters/pty-transport.ts +2 -1
  214. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  215. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  216. package/src/cli-adapters/resolve-executable.ts +204 -0
  217. package/src/cli-adapters/session-host-transport.ts +2 -1
  218. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  219. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  220. package/src/cli-adapters/terminal-screen.ts +16 -81
  221. package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
  222. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  223. package/src/commands/chat-commands-read.ts +2488 -0
  224. package/src/commands/chat-commands-scope.ts +54 -0
  225. package/src/commands/chat-commands-shared.ts +114 -0
  226. package/src/commands/chat-commands-write.ts +891 -0
  227. package/src/commands/chat-commands.ts +19 -1841
  228. package/src/commands/cli-manager.ts +596 -27
  229. package/src/commands/handler.ts +841 -2
  230. package/src/commands/high-family/index.ts +28 -0
  231. package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
  232. package/src/commands/high-family/mesh-events.ts +89 -0
  233. package/src/commands/high-family/mesh-status.ts +822 -0
  234. package/src/commands/high-family/types.ts +80 -0
  235. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  236. package/src/commands/low-family/daemon-lifecycle.ts +107 -0
  237. package/src/commands/low-family/diagnostics.ts +57 -0
  238. package/src/commands/low-family/index.ts +37 -0
  239. package/src/commands/low-family/mesh-ledger.ts +62 -0
  240. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  241. package/src/commands/low-family/notification.ts +116 -0
  242. package/src/commands/low-family/refine-config.ts +106 -0
  243. package/src/commands/low-family/session-host.ts +274 -0
  244. package/src/commands/low-family/spec-providerdev.ts +217 -0
  245. package/src/commands/low-family/status-meta.ts +112 -0
  246. package/src/commands/low-family/types.ts +39 -0
  247. package/src/commands/med-family/cli-agent.ts +238 -0
  248. package/src/commands/med-family/fast-forward.ts +230 -0
  249. package/src/commands/med-family/ide.ts +163 -0
  250. package/src/commands/med-family/index.ts +37 -0
  251. package/src/commands/med-family/mesh-crud.ts +1253 -0
  252. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  253. package/src/commands/med-family/mesh-queue.ts +167 -0
  254. package/src/commands/med-family/mesh-restart.ts +92 -0
  255. package/src/commands/med-family/types.ts +153 -0
  256. package/src/commands/mesh-coordinator.ts +334 -124
  257. package/src/commands/router.ts +2893 -3536
  258. package/src/commands/stream-commands.ts +8 -0
  259. package/src/commands/upgrade-helper.ts +310 -45
  260. package/src/config/chat-history.ts +493 -24
  261. package/src/config/config.ts +12 -0
  262. package/src/config/mesh-config.ts +619 -23
  263. package/src/config/mesh-json-config.ts +376 -0
  264. package/src/config/recent-activity.ts +8 -2
  265. package/src/config/repo-settings.ts +111 -0
  266. package/src/daemon/dev-auto-implement.ts +3 -2
  267. package/src/daemon/dev-cli-debug.ts +10 -1
  268. package/src/daemon/dev-server.ts +0 -541
  269. package/src/detection/cli-detector.ts +28 -9
  270. package/src/detection/ide-detector.ts +55 -16
  271. package/src/detection/win32-ide-version.ts +106 -0
  272. package/src/git/change-impact-config.ts +354 -0
  273. package/src/git/git-commands.ts +78 -15
  274. package/src/git/git-diff.ts +81 -11
  275. package/src/git/git-executor.ts +12 -0
  276. package/src/git/git-status.ts +767 -48
  277. package/src/git/git-types.ts +14 -62
  278. package/src/git/git-worktree.ts +261 -4
  279. package/src/git/index.ts +17 -0
  280. package/src/index.ts +198 -12
  281. package/src/installer.d.ts +1 -1
  282. package/src/installer.ts +8 -6
  283. package/src/ipc/local-ipc-server.ts +278 -0
  284. package/src/launch.d.ts +1 -1
  285. package/src/launch.ts +37 -28
  286. package/src/logging/async-batch-writer.ts +55 -0
  287. package/src/logging/command-log.ts +7 -5
  288. package/src/logging/log-redactor.ts +100 -0
  289. package/src/logging/log-tail-reader.ts +341 -0
  290. package/src/logging/logger.ts +14 -7
  291. package/src/mesh/contracts.ts +338 -0
  292. package/src/mesh/coordinator-prompt.ts +416 -34
  293. package/src/mesh/coordinator-registry.ts +121 -0
  294. package/src/mesh/mesh-active-work.ts +645 -0
  295. package/src/mesh/mesh-clone-grace.ts +68 -0
  296. package/src/mesh/mesh-coordinator-config.ts +97 -0
  297. package/src/mesh/mesh-delivery-policy.ts +315 -0
  298. package/src/mesh/mesh-event-classify.ts +51 -0
  299. package/src/mesh/mesh-event-forwarding.ts +1897 -0
  300. package/src/mesh/mesh-event-trace.ts +67 -0
  301. package/src/mesh/mesh-events-coordinator.ts +32 -0
  302. package/src/mesh/mesh-events-pending.ts +656 -0
  303. package/src/mesh/mesh-events-stale.ts +389 -0
  304. package/src/mesh/mesh-events-utils.ts +443 -0
  305. package/src/mesh/mesh-events.ts +33 -1035
  306. package/src/mesh/mesh-fast-forward.ts +843 -0
  307. package/src/mesh/mesh-host-ownership.ts +111 -0
  308. package/src/mesh/mesh-init.ts +350 -0
  309. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  310. package/src/mesh/mesh-ledger.ts +841 -102
  311. package/src/mesh/mesh-magi-status.ts +223 -0
  312. package/src/mesh/mesh-missions.ts +449 -0
  313. package/src/mesh/mesh-node-identity.ts +1985 -0
  314. package/src/mesh/mesh-queue-assignment.ts +1924 -0
  315. package/src/mesh/mesh-reconcile-loop.ts +2018 -0
  316. package/src/mesh/mesh-refine-batch.ts +205 -0
  317. package/src/mesh/mesh-refine-gates.ts +1673 -0
  318. package/src/mesh/mesh-refine-status.ts +231 -0
  319. package/src/mesh/mesh-review-inbox.ts +307 -0
  320. package/src/mesh/mesh-routing.ts +291 -0
  321. package/src/mesh/mesh-runtime-store.ts +1853 -0
  322. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  323. package/src/mesh/mesh-task-inflight.ts +70 -0
  324. package/src/mesh/mesh-task-stats.ts +161 -0
  325. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  326. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  327. package/src/mesh/mesh-work-queue.ts +1254 -141
  328. package/src/mesh/preview-freshness.ts +118 -0
  329. package/src/mesh/refine-config.ts +423 -0
  330. package/src/mesh/worktree-bootstrap-config.ts +450 -0
  331. package/src/providers/acp-provider-instance.ts +43 -10
  332. package/src/providers/approval-utils.d.ts +5 -0
  333. package/src/providers/approval-utils.ts +57 -5
  334. package/src/providers/chat-message-normalization.ts +92 -4
  335. package/src/providers/cli-provider-instance.ts +2177 -107
  336. package/src/providers/contracts.d.ts +55 -0
  337. package/src/providers/contracts.ts +160 -6
  338. package/src/providers/extension-provider-instance.ts +12 -7
  339. package/src/providers/external-sources.ts +218 -0
  340. package/src/providers/ide-provider-instance.ts +35 -12
  341. package/src/providers/manual-attendance.ts +85 -0
  342. package/src/providers/native-history/antigravity-cli-transcript.ts +1043 -0
  343. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  344. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  345. package/src/providers/native-history/constants.ts +19 -0
  346. package/src/providers/native-history/dispatcher.ts +373 -0
  347. package/src/providers/native-history/hermes-cli-transcript.ts +260 -0
  348. package/src/providers/native-history/index.ts +30 -0
  349. package/src/providers/provider-instance-manager.ts +71 -0
  350. package/src/providers/provider-instance.ts +19 -1
  351. package/src/providers/provider-loader.ts +668 -50
  352. package/src/providers/provider-schema.ts +87 -14
  353. package/src/providers/provider-trust.ts +114 -0
  354. package/src/providers/read-chat-contract.ts +76 -16
  355. package/src/providers/sdk/README.md +49 -0
  356. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  357. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  358. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  359. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  360. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  361. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  362. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  363. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  364. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  365. package/src/providers/sdk/v1/index.ts +152 -0
  366. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  367. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  368. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  369. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +509 -0
  370. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  371. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  372. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  373. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  374. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  375. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  376. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  377. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  378. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  379. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  380. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  381. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  382. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  383. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  384. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  385. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  386. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  387. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  388. package/src/providers/sdk/v1/validators/index.ts +19 -0
  389. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  390. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  391. package/src/providers/spec/adapter.ts +246 -0
  392. package/src/providers/spec/cli-adapter.ts +1064 -0
  393. package/src/providers/spec/evaluator.ts +407 -0
  394. package/src/providers/spec/fsm-driver.ts +1481 -0
  395. package/src/providers/spec/fsm-evaluator.ts +290 -0
  396. package/src/providers/spec/fsm-loader.ts +128 -0
  397. package/src/providers/spec/fsm-types.ts +301 -0
  398. package/src/providers/spec/native-history-executor.ts +1174 -0
  399. package/src/providers/spec/pre-launch-trust.ts +104 -0
  400. package/src/providers/spec/route.ts +51 -0
  401. package/src/providers/spec/types.ts +262 -0
  402. package/src/providers/status-monitor.d.ts +7 -7
  403. package/src/providers/status-monitor.ts +37 -22
  404. package/src/providers/transcript-v2.ts +567 -0
  405. package/src/providers/types/interactive-prompt.ts +536 -0
  406. package/src/providers/version-archive.ts +64 -24
  407. package/src/providers/working-dir.ts +23 -0
  408. package/src/repo-mesh-types.ts +758 -14
  409. package/src/runtime-defaults.ts +39 -0
  410. package/src/session-host/managed-host.ts +218 -0
  411. package/src/sessions/registry.ts +6 -0
  412. package/src/shared-types-extra.ts +2 -4
  413. package/src/shared-types.d.ts +8 -0
  414. package/src/shared-types.ts +64 -1
  415. package/src/status/builders.ts +26 -6
  416. package/src/status/normalize.ts +2 -0
  417. package/src/status/reporter.ts +19 -1
  418. package/src/status/snapshot.ts +95 -26
  419. package/src/system/hash.ts +23 -0
  420. package/src/system/host-memory.ts +29 -12
  421. package/src/system/load-better-sqlite3.ts +68 -0
  422. package/src/types.ts +5 -0
  423. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  424. package/dist/mesh/mesh-sync.d.ts +0 -53
  425. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  426. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  427. package/src/mesh/mesh-sync.ts +0 -111
@@ -8,8 +8,9 @@
8
8
 
9
9
  import { existsSync, readFileSync, writeFileSync } from 'fs';
10
10
  import { join } from 'path';
11
- import { randomUUID } from 'crypto';
12
- import { getConfigDir } from './config.js';
11
+ import { randomBytes, randomUUID } from 'crypto';
12
+ import { shortHash } from '../system/hash.js';
13
+ import { getConfigDir, loadConfig } from './config.js';
13
14
  import type {
14
15
  LocalMeshConfig,
15
16
  LocalMeshEntry,
@@ -18,8 +19,12 @@ import type {
18
19
  RepoMeshNodePolicy,
19
20
  RepoMeshNodeCapabilities,
20
21
  RepoMeshCoordinatorConfig,
22
+ RepoMeshHostMetadata,
23
+ RepoMeshDaemonRole,
21
24
  } from '../repo-mesh-types.js';
22
- import { DEFAULT_MESH_POLICY } from '../repo-mesh-types.js';
25
+ import type { MagiPanel, MagiPanelMember, MagiPanelDefaultKind, MagiKindPanelMap, MagiSlot, MagiTaskKind } from '@adhdev/mesh-shared';
26
+ import { mergeAndNormalizePolicy } from '../repo-mesh-types.js';
27
+ import { createDefaultMeshHostMetadata } from '../mesh/mesh-host-ownership.js';
23
28
 
24
29
  // ─── Persistence ────────────────────────────────
25
30
 
@@ -33,12 +38,85 @@ function loadMeshConfig(): LocalMeshConfig {
33
38
  try {
34
39
  const raw = JSON.parse(readFileSync(path, 'utf-8'));
35
40
  if (!raw || !Array.isArray(raw.meshes)) return { meshes: [] };
36
- return raw as LocalMeshConfig;
41
+ const config = raw as LocalMeshConfig;
42
+ const migrated = migrateLoadedMeshConfig(config);
43
+ // Persist eagerly when the on-load migration changed anything, so the
44
+ // dead field is gone from disk even on a pure-read path (mesh_status /
45
+ // mesh_list_nodes) that never otherwise mutates the config. Best-effort:
46
+ // a write failure (e.g. read-only fs) must not break reads, so swallow.
47
+ if (migrated) {
48
+ try {
49
+ saveMeshConfig(config);
50
+ } catch {
51
+ // keep the in-memory strip; disk converges on the next mutating op
52
+ }
53
+ }
54
+ return config;
37
55
  } catch {
38
56
  return { meshes: [] };
39
57
  }
40
58
  }
41
59
 
60
+ /**
61
+ * In-place migration applied to every loaded meshes.json. Strips data that
62
+ * outlived the feature that wrote it so the persisted config converges on the
63
+ * current schema the next time it is saved.
64
+ *
65
+ * Currently: drops the dead `role` field from each node policy's providerRoles
66
+ * entries. providerRoles is retained for its `maxParallel` per-(node, provider)
67
+ * cap, but the routing `role` was removed (routing is governed solely by
68
+ * required_tags). A meshes.json written before the removal still carries
69
+ * `role: "validator"` etc.; this drops it on load so mesh_status / mesh_list_nodes
70
+ * never surface the dead field and the next saveMeshConfig() persists it gone.
71
+ *
72
+ * Returns true when the config was mutated (caller may persist eagerly).
73
+ */
74
+ function migrateLoadedMeshConfig(config: LocalMeshConfig): boolean {
75
+ let changed = false;
76
+ for (const mesh of config.meshes) {
77
+ if (!mesh || !Array.isArray(mesh.nodes)) continue;
78
+ for (const node of mesh.nodes) {
79
+ if (stripDeadRoleFromProviderRoles(node?.policy)) changed = true;
80
+ }
81
+ }
82
+ return changed;
83
+ }
84
+
85
+ /**
86
+ * Drop the legacy `role` field from each providerRoles entry of a node policy,
87
+ * in place. Keeps providerType + maxParallel (the still-meaningful per-(node,
88
+ * provider) cap). Defensive against malformed entries — non-object items are
89
+ * left untouched. Returns true when at least one `role` field was removed.
90
+ */
91
+ function stripDeadRoleFromProviderRoles(policy: unknown): boolean {
92
+ if (!policy || typeof policy !== 'object') return false;
93
+ const roles = (policy as { providerRoles?: unknown }).providerRoles;
94
+ if (!Array.isArray(roles)) return false;
95
+ let changed = false;
96
+ for (const entry of roles) {
97
+ if (entry && typeof entry === 'object' && !Array.isArray(entry)
98
+ && Object.prototype.hasOwnProperty.call(entry, 'role')) {
99
+ delete (entry as Record<string, unknown>).role;
100
+ changed = true;
101
+ }
102
+ }
103
+ return changed;
104
+ }
105
+
106
+ function normalizeCapabilityTags(value: unknown): string[] | undefined {
107
+ if (!Array.isArray(value)) return undefined;
108
+ const seen = new Set<string>();
109
+ const tags = value
110
+ .map(tag => typeof tag === 'string' ? tag.trim() : '')
111
+ .filter(Boolean)
112
+ .filter(tag => {
113
+ if (seen.has(tag)) return false;
114
+ seen.add(tag);
115
+ return true;
116
+ });
117
+ return tags.length ? tags : undefined;
118
+ }
119
+
42
120
  function saveMeshConfig(config: LocalMeshConfig): void {
43
121
  const path = getMeshConfigPath();
44
122
  writeFileSync(path, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 });
@@ -74,24 +152,11 @@ export function normalizeRepoIdentity(remoteUrl: string): string {
74
152
 
75
153
  // ─── CRUD Operations ────────────────────────────
76
154
 
77
- const SESSION_CLEANUP_MODES = new Set(['preserve', 'stop', 'delete_stopped', 'stop_and_delete']);
78
- const SPAWNED_SESSION_VISIBILITY_MODES = new Set(['visible', 'hidden']);
79
-
80
- function mergeMeshPolicy(base: RepoMeshPolicy | undefined, patch: Partial<RepoMeshPolicy> | undefined): RepoMeshPolicy {
81
- const policy: RepoMeshPolicy = { ...DEFAULT_MESH_POLICY, ...(base || {}), ...(patch || {}) };
82
- if (!['block', 'warn', 'checkpoint_then_continue'].includes(policy.dirtyWorkspaceBehavior)) {
83
- policy.dirtyWorkspaceBehavior = 'warn';
84
- }
85
- const maxParallelTasks = Number(policy.maxParallelTasks);
86
- policy.maxParallelTasks = Number.isFinite(maxParallelTasks) ? Math.max(1, Math.min(8, Math.floor(maxParallelTasks))) : 2;
87
- if (!SESSION_CLEANUP_MODES.has(String(policy.sessionCleanupOnNodeRemove))) {
88
- policy.sessionCleanupOnNodeRemove = 'preserve';
89
- }
90
- if (!SPAWNED_SESSION_VISIBILITY_MODES.has(String(policy.spawnedSessionVisibility))) {
91
- policy.spawnedSessionVisibility = 'visible';
92
- }
93
- return policy;
94
- }
155
+ // Single source of truth for default+merge+per-field normalization is
156
+ // mergeAndNormalizePolicy in repo-mesh-types.ts. This thin alias keeps the local
157
+ // call sites (createMesh/updateMesh) reading naturally while ensuring config
158
+ // writes go through the exact same normalizer the scheduler/display paths use.
159
+ const mergeMeshPolicy = mergeAndNormalizePolicy;
95
160
 
96
161
  export function listMeshes(): LocalMeshEntry[] {
97
162
  return loadMeshConfig().meshes;
@@ -112,6 +177,7 @@ export interface CreateMeshOptions {
112
177
  defaultBranch?: string;
113
178
  policy?: Partial<RepoMeshPolicy>;
114
179
  coordinator?: RepoMeshCoordinatorConfig;
180
+ meshHost?: RepoMeshHostMetadata;
115
181
  }
116
182
 
117
183
  export function createMesh(opts: CreateMeshOptions): LocalMeshEntry {
@@ -133,6 +199,7 @@ export function createMesh(opts: CreateMeshOptions): LocalMeshEntry {
133
199
  defaultBranch: opts.defaultBranch,
134
200
  policy: mergeMeshPolicy(undefined, opts.policy),
135
201
  coordinator: opts.coordinator || {},
202
+ meshHost: opts.meshHost || createDefaultMeshHostMetadata(),
136
203
  nodes: [],
137
204
  createdAt: now,
138
205
  updatedAt: now,
@@ -148,6 +215,7 @@ export interface UpdateMeshOptions {
148
215
  defaultBranch?: string;
149
216
  policy?: Partial<RepoMeshPolicy>;
150
217
  coordinator?: RepoMeshCoordinatorConfig;
218
+ meshHost?: RepoMeshHostMetadata;
151
219
  }
152
220
 
153
221
  export function updateMesh(meshId: string, opts: UpdateMeshOptions): LocalMeshEntry | undefined {
@@ -159,6 +227,7 @@ export function updateMesh(meshId: string, opts: UpdateMeshOptions): LocalMeshEn
159
227
  if (opts.defaultBranch !== undefined) mesh.defaultBranch = opts.defaultBranch;
160
228
  if (opts.policy) mesh.policy = mergeMeshPolicy(mesh.policy, opts.policy);
161
229
  if (opts.coordinator) mesh.coordinator = opts.coordinator;
230
+ if (opts.meshHost) mesh.meshHost = opts.meshHost;
162
231
  mesh.updatedAt = new Date().toISOString();
163
232
 
164
233
  saveMeshConfig(config);
@@ -174,6 +243,240 @@ export function deleteMesh(meshId: string): boolean {
174
243
  return true;
175
244
  }
176
245
 
246
+ function normalizeManualHostAddress(hostAddress: string): string {
247
+ const normalized = hostAddress.trim().replace(/\/+$/, '');
248
+ if (!normalized) throw new Error('hostAddress required');
249
+ let parsed: URL;
250
+ try {
251
+ parsed = new URL(normalized);
252
+ } catch {
253
+ throw new Error('hostAddress must be a valid http(s) or ws(s) URL');
254
+ }
255
+ if (!['http:', 'https:', 'ws:', 'wss:'].includes(parsed.protocol)) {
256
+ throw new Error('hostAddress must use http, https, ws, or wss');
257
+ }
258
+ return normalized;
259
+ }
260
+
261
+ export function tokenIdForManualPairing(token: string): string {
262
+ return `tok_${shortHash(token)}`;
263
+ }
264
+
265
+ function normalizeTokenExpiry(value: unknown): string | undefined {
266
+ if (typeof value !== 'string' || !value.trim()) return undefined;
267
+ const date = new Date(value);
268
+ if (Number.isNaN(date.getTime())) throw new Error('expiresAt must be a valid ISO date');
269
+ return date.toISOString();
270
+ }
271
+
272
+ function assertPairingTokenValid(pairing: RepoMeshHostMetadata['pairing'], rawToken: string, nowIso: string): { ok: true; tokenId: string } | { ok: false; reason: string; expectedTokenId?: string; presentedTokenId?: string } {
273
+ const token = rawToken.trim();
274
+ if (!token) return { ok: false, reason: 'token required' };
275
+ const presentedTokenId = tokenIdForManualPairing(token);
276
+ const expectedTokenId = pairing?.tokenId;
277
+ if (!expectedTokenId || pairing?.status === 'not_configured' || pairing?.status === 'revoked') {
278
+ return { ok: false, reason: 'host pairing token is not configured', presentedTokenId };
279
+ }
280
+ if (pairing.expiresAt && new Date(pairing.expiresAt).getTime() <= new Date(nowIso).getTime()) {
281
+ return { ok: false, reason: 'host pairing token expired', expectedTokenId, presentedTokenId };
282
+ }
283
+ if (presentedTokenId !== expectedTokenId) {
284
+ return { ok: false, reason: 'invalid pairing token', expectedTokenId, presentedTokenId };
285
+ }
286
+ return { ok: true, tokenId: presentedTokenId };
287
+ }
288
+
289
+ export interface ConfigureMeshHostPairingOptions {
290
+ hostAddress: string;
291
+ token: string;
292
+ now?: string;
293
+ }
294
+
295
+ export function configureMeshHostPairing(
296
+ meshId: string,
297
+ opts: ConfigureMeshHostPairingOptions,
298
+ ): { mesh: LocalMeshEntry; meshHost: RepoMeshHostMetadata; hostAddress: string } | undefined {
299
+ const hostAddress = normalizeManualHostAddress(opts.hostAddress);
300
+ const token = opts.token.trim();
301
+ if (!token) throw new Error('token required');
302
+
303
+ const config = loadMeshConfig();
304
+ const mesh = config.meshes.find(m => m.id === meshId);
305
+ if (!mesh) return undefined;
306
+
307
+ const now = opts.now || new Date().toISOString();
308
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
309
+ const meshHost: RepoMeshHostMetadata = {
310
+ ...previous,
311
+ role: 'member',
312
+ hostAddress,
313
+ pairing: {
314
+ status: 'pairing',
315
+ tokenId: tokenIdForManualPairing(token),
316
+ lastPairedAt: now,
317
+ },
318
+ };
319
+
320
+ mesh.meshHost = meshHost;
321
+ mesh.updatedAt = now;
322
+ saveMeshConfig(config);
323
+ return { mesh, meshHost, hostAddress };
324
+ }
325
+
326
+ export interface CreateMeshHostPairingTokenOptions {
327
+ token?: string;
328
+ expiresAt?: string;
329
+ now?: string;
330
+ }
331
+
332
+ export function createMeshHostPairingToken(
333
+ meshId: string,
334
+ opts: CreateMeshHostPairingTokenOptions = {},
335
+ ): { mesh: LocalMeshEntry; meshHost: RepoMeshHostMetadata; token: string; tokenId: string; expiresAt?: string } | undefined {
336
+ const config = loadMeshConfig();
337
+ const mesh = config.meshes.find(m => m.id === meshId);
338
+ if (!mesh) return undefined;
339
+ const now = opts.now || new Date().toISOString();
340
+ const token = (opts.token || `mhj_${randomBytes(24).toString('base64url')}`).trim();
341
+ if (!token) throw new Error('token required');
342
+ const tokenId = tokenIdForManualPairing(token);
343
+ const expiresAt = normalizeTokenExpiry(opts.expiresAt);
344
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
345
+ if (previous.role === 'member') {
346
+ throw new Error('Mesh Host daemon required to create host pairing tokens; member daemons cannot mint host join tokens.');
347
+ }
348
+ const meshHost: RepoMeshHostMetadata = {
349
+ ...previous,
350
+ role: 'host',
351
+ pairing: {
352
+ status: 'pairing',
353
+ tokenId,
354
+ lastPairedAt: now,
355
+ ...(expiresAt ? { expiresAt } : {}),
356
+ },
357
+ };
358
+ mesh.meshHost = meshHost;
359
+ mesh.updatedAt = now;
360
+ saveMeshConfig(config);
361
+ return { mesh, meshHost, token, tokenId, ...(expiresAt ? { expiresAt } : {}) };
362
+ }
363
+
364
+ export interface MeshHostJoinMemberNodeInput {
365
+ id?: string;
366
+ workspace: string;
367
+ repoRoot?: string;
368
+ daemonId?: string;
369
+ machineId?: string;
370
+ userOverrides?: Partial<RepoMeshNodeCapabilities>;
371
+ policy?: RepoMeshNodePolicy;
372
+ role?: RepoMeshDaemonRole;
373
+ }
374
+
375
+ export interface ApplyMeshHostJoinOptions {
376
+ token: string;
377
+ memberNode: MeshHostJoinMemberNodeInput;
378
+ memberMeshId?: string;
379
+ now?: string;
380
+ }
381
+
382
+ export function applyMeshHostJoinRequest(
383
+ meshId: string,
384
+ opts: ApplyMeshHostJoinOptions,
385
+ ): { accepted: true; mesh: LocalMeshEntry; meshHost: RepoMeshHostMetadata; node: LocalMeshNodeEntry; tokenId: string } | { accepted: false; mesh?: LocalMeshEntry; meshHost?: RepoMeshHostMetadata; tokenId?: string; reason: string } | undefined {
386
+ const config = loadMeshConfig();
387
+ const mesh = config.meshes.find(m => m.id === meshId);
388
+ if (!mesh) return undefined;
389
+ const now = opts.now || new Date().toISOString();
390
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
391
+ if (previous.role === 'member') {
392
+ return { accepted: false, mesh, meshHost: previous, reason: 'Mesh Host daemon required to accept join requests' };
393
+ }
394
+ const meshHost: RepoMeshHostMetadata = { ...previous, role: 'host' };
395
+ const validation = assertPairingTokenValid(meshHost.pairing, opts.token, now);
396
+ if (!validation.ok) {
397
+ mesh.meshHost = {
398
+ ...meshHost,
399
+ pairing: {
400
+ ...(meshHost.pairing || { status: 'not_configured' as const }),
401
+ status: 'rejected',
402
+ lastRejectedAt: now,
403
+ },
404
+ };
405
+ mesh.updatedAt = now;
406
+ saveMeshConfig(config);
407
+ return { accepted: false, mesh, meshHost: mesh.meshHost, tokenId: validation.presentedTokenId, reason: validation.reason };
408
+ }
409
+
410
+ const workspace = opts.memberNode.workspace.trim();
411
+ if (!workspace) throw new Error('memberNode.workspace required');
412
+ const memberId = opts.memberNode.id?.trim();
413
+ let node = mesh.nodes.find(n => (memberId && n.id === memberId) || n.workspace === workspace);
414
+ if (node) {
415
+ node.workspace = workspace;
416
+ node.repoRoot = opts.memberNode.repoRoot;
417
+ node.daemonId = opts.memberNode.daemonId;
418
+ node.machineId = opts.memberNode.machineId;
419
+ node.userOverrides = opts.memberNode.userOverrides || node.userOverrides || {};
420
+ node.policy = { ...(node.policy || {}), ...(opts.memberNode.policy || {}) };
421
+ node.role = 'member';
422
+ } else {
423
+ if (mesh.nodes.length >= 10) throw new Error('Maximum 10 nodes per mesh');
424
+ node = {
425
+ id: memberId || `node_${randomUUID().replace(/-/g, '')}`,
426
+ workspace,
427
+ repoRoot: opts.memberNode.repoRoot,
428
+ daemonId: opts.memberNode.daemonId,
429
+ machineId: opts.memberNode.machineId,
430
+ userOverrides: opts.memberNode.userOverrides || {},
431
+ policy: opts.memberNode.policy || {},
432
+ role: 'member',
433
+ };
434
+ mesh.nodes.push(node);
435
+ }
436
+ mesh.meshHost = {
437
+ ...meshHost,
438
+ pairing: {
439
+ ...(meshHost.pairing || {}),
440
+ status: 'paired',
441
+ tokenId: validation.tokenId,
442
+ joinedAt: now,
443
+ lastPairedAt: meshHost.pairing?.lastPairedAt || now,
444
+ ...(meshHost.pairing?.expiresAt ? { expiresAt: meshHost.pairing.expiresAt } : {}),
445
+ },
446
+ };
447
+ mesh.updatedAt = now;
448
+ saveMeshConfig(config);
449
+ return { accepted: true, mesh, meshHost: mesh.meshHost, node, tokenId: validation.tokenId };
450
+ }
451
+
452
+ export function markMeshHostPairingJoined(
453
+ meshId: string,
454
+ opts: { hostDaemonId?: string; hostNodeId?: string; joinedAt?: string; token?: string; tokenId?: string },
455
+ ): { mesh: LocalMeshEntry; meshHost: RepoMeshHostMetadata } | undefined {
456
+ const config = loadMeshConfig();
457
+ const mesh = config.meshes.find(m => m.id === meshId);
458
+ if (!mesh) return undefined;
459
+ const now = opts.joinedAt || new Date().toISOString();
460
+ const previous = mesh.meshHost || createDefaultMeshHostMetadata();
461
+ const tokenId = opts.tokenId || (opts.token ? tokenIdForManualPairing(opts.token) : previous.pairing?.tokenId);
462
+ mesh.meshHost = {
463
+ ...previous,
464
+ role: 'member',
465
+ ...(opts.hostDaemonId ? { hostDaemonId: opts.hostDaemonId } : {}),
466
+ ...(opts.hostNodeId ? { hostNodeId: opts.hostNodeId } : {}),
467
+ pairing: {
468
+ ...(previous.pairing || {}),
469
+ status: 'paired',
470
+ ...(tokenId ? { tokenId } : {}),
471
+ joinedAt: now,
472
+ lastPairedAt: previous.pairing?.lastPairedAt || now,
473
+ },
474
+ };
475
+ mesh.updatedAt = now;
476
+ saveMeshConfig(config);
477
+ return { mesh, meshHost: mesh.meshHost };
478
+ }
479
+
177
480
  // ─── Node Operations ────────────────────────────
178
481
 
179
482
  export interface AddNodeOptions {
@@ -181,11 +484,19 @@ export interface AddNodeOptions {
181
484
  repoRoot?: string;
182
485
  daemonId?: string;
183
486
  machineId?: string;
487
+ capabilities?: string[];
184
488
  userOverrides?: Partial<RepoMeshNodeCapabilities>;
185
489
  policy?: RepoMeshNodePolicy;
186
490
  isLocalWorktree?: boolean;
187
491
  worktreeBranch?: string;
188
492
  clonedFromNodeId?: string;
493
+ worktreeBootstrap?: LocalMeshNodeEntry['worktreeBootstrap'];
494
+ role?: RepoMeshDaemonRole;
495
+ /** Owning daemon's machine nickname. Defaults to this daemon's local
496
+ * config.machineNickname when omitted — a node is always added by (and on)
497
+ * the daemon that owns its workspace (self/base node or a local worktree
498
+ * clone), so the local config is the correct source. */
499
+ machineNickname?: string;
189
500
  }
190
501
 
191
502
  export function addNode(meshId: string, opts: AddNodeOptions): LocalMeshNodeEntry | undefined {
@@ -202,17 +513,35 @@ export function addNode(meshId: string, opts: AddNodeOptions): LocalMeshNodeEntr
202
513
  throw new Error('This workspace is already in the mesh');
203
514
  }
204
515
 
516
+ // A node is always added by the daemon that owns its workspace (the self/base
517
+ // node, or a local worktree clone spawned from this daemon), so this daemon's
518
+ // config.machineNickname is the correct owner nickname. Explicit opt wins.
519
+ const machineNickname = (() => {
520
+ const explicit = typeof opts.machineNickname === 'string' ? opts.machineNickname.trim() : '';
521
+ if (explicit) return explicit;
522
+ try {
523
+ const local = loadConfig().machineNickname;
524
+ return typeof local === 'string' && local.trim() ? local.trim() : undefined;
525
+ } catch {
526
+ return undefined;
527
+ }
528
+ })();
529
+
205
530
  const node: LocalMeshNodeEntry = {
206
531
  id: `node_${randomUUID().replace(/-/g, '')}`,
207
532
  workspace: opts.workspace.trim(),
208
533
  repoRoot: opts.repoRoot,
209
534
  daemonId: opts.daemonId,
210
535
  machineId: opts.machineId,
536
+ ...(machineNickname ? { machineNickname } : {}),
537
+ capabilities: normalizeCapabilityTags(opts.capabilities),
211
538
  userOverrides: opts.userOverrides || {},
212
539
  policy: opts.policy || {},
213
540
  isLocalWorktree: opts.isLocalWorktree,
214
541
  worktreeBranch: opts.worktreeBranch,
215
542
  clonedFromNodeId: opts.clonedFromNodeId,
543
+ worktreeBootstrap: opts.worktreeBootstrap,
544
+ role: opts.role,
216
545
  };
217
546
 
218
547
  mesh.nodes.push(node);
@@ -238,7 +567,23 @@ export function removeNode(meshId: string, nodeId: string): boolean {
238
567
  export function updateNode(
239
568
  meshId: string,
240
569
  nodeId: string,
241
- opts: { userOverrides?: Partial<RepoMeshNodeCapabilities>; policy?: RepoMeshNodePolicy },
570
+ opts: {
571
+ userOverrides?: Partial<RepoMeshNodeCapabilities>;
572
+ policy?: RepoMeshNodePolicy;
573
+ worktreeBootstrap?: LocalMeshNodeEntry['worktreeBootstrap'];
574
+ /** Per-node instruction surfaced in the coordinator prompt. Pass an
575
+ * empty string or undefined to clear it. */
576
+ systemPrompt?: string;
577
+ /** Live self-reported platform/arch from the owning daemon's git_status
578
+ * envelope. Persisted distinctly from userOverrides (auto-detected, not
579
+ * operator intent) so capability-tag os=/arch= self-heals across loads. */
580
+ reportedPlatform?: string;
581
+ reportedArch?: string;
582
+ /** Owning daemon's self-reported machine nickname, carried on the
583
+ * git_status envelope. Persisted so the friendly label survives across
584
+ * coordinator restarts (mirrors reportedPlatform/reportedArch). */
585
+ reportedMachineNickname?: string;
586
+ },
242
587
  ): LocalMeshNodeEntry | undefined {
243
588
  const config = loadMeshConfig();
244
589
  const mesh = config.meshes.find(m => m.id === meshId);
@@ -248,8 +593,259 @@ export function updateNode(
248
593
  if (!node) return undefined;
249
594
 
250
595
  if (opts.userOverrides) node.userOverrides = { ...node.userOverrides, ...opts.userOverrides };
596
+ if (opts.reportedPlatform && opts.reportedPlatform.trim()) node.reportedPlatform = opts.reportedPlatform.trim();
597
+ if (opts.reportedArch && opts.reportedArch.trim()) node.reportedArch = opts.reportedArch.trim();
598
+ if (opts.reportedMachineNickname && opts.reportedMachineNickname.trim()) node.machineNickname = opts.reportedMachineNickname.trim();
251
599
  if (opts.policy) node.policy = { ...node.policy, ...opts.policy };
600
+ if (opts.worktreeBootstrap) node.worktreeBootstrap = opts.worktreeBootstrap;
601
+ if (Object.prototype.hasOwnProperty.call(opts, 'systemPrompt')) {
602
+ // Honor explicit clears: { systemPrompt: undefined } drops the field.
603
+ if (opts.systemPrompt && opts.systemPrompt.trim()) {
604
+ node.systemPrompt = opts.systemPrompt;
605
+ } else {
606
+ delete node.systemPrompt;
607
+ }
608
+ }
252
609
  mesh.updatedAt = new Date().toISOString();
253
610
  saveMeshConfig(config);
254
611
  return node;
255
612
  }
613
+
614
+ // ─── MAGI Panels (machine-local cross-verification quorums) ──
615
+
616
+ /** Hard cap on members per panel — a sanity bound, not the per-invocation replica cap. */
617
+ const MAX_MAGI_PANEL_MEMBERS = 24;
618
+
619
+ function normalizeReplicaCount(value: unknown): number | undefined {
620
+ if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;
621
+ const n = Math.floor(value);
622
+ return n >= 1 ? n : undefined;
623
+ }
624
+
625
+ /**
626
+ * Normalize a panel `defaultKind` (the non-binding default output kind). Returns
627
+ * undefined (drop, don't throw) for any absent / unknown value so a stray field
628
+ * never blocks a panel write. 'freeform' is explicitly DROPPED with a warning: a
629
+ * panel is a cross-verification tool and freeform contributes no structured claims
630
+ * (claims:[]), so defaulting to it would silently zero out the very thing the panel
631
+ * exists for. Only the evidence-bearing kinds (claim_audit / rca / design) survive.
632
+ */
633
+ function normalizeMagiPanelDefaultKind(raw: unknown): MagiPanelDefaultKind | undefined {
634
+ if (raw == null) return undefined;
635
+ const s = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
636
+ if (s === 'claim_audit' || s === 'rca' || s === 'design') return s;
637
+ if (s === 'freeform') {
638
+ // eslint-disable-next-line no-console
639
+ console.warn(
640
+ "[magi] panel defaultKind='freeform' rejected — freeform contributes no structured claims to cross-verification; dropping (use claim_audit / rca / design, or omit).",
641
+ );
642
+ return undefined;
643
+ }
644
+ // Any other value (typo / unsupported kind): drop silently — the panel still
645
+ // resolves to the claim_audit fallback at review time.
646
+ return undefined;
647
+ }
648
+
649
+ /**
650
+ * Validate + normalize a panel config before persisting. Mirrors the node-config
651
+ * normalization style (mesh-config addNode/updateNode): trims strings, drops
652
+ * empties, requires a provider per member, clamps replica counts. Throws on
653
+ * structurally invalid input so the calling tool returns a clear error rather than
654
+ * writing a malformed panel.
655
+ */
656
+ export function normalizeMagiPanel(config: unknown): MagiPanel {
657
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
658
+ throw new Error('invalid_magi_panel: config must be an object');
659
+ }
660
+ const raw = config as Record<string, unknown>;
661
+ const rawMembers = raw.members;
662
+ if (!Array.isArray(rawMembers) || rawMembers.length === 0) {
663
+ throw new Error('invalid_magi_panel: members must be a non-empty array');
664
+ }
665
+ if (rawMembers.length > MAX_MAGI_PANEL_MEMBERS) {
666
+ throw new Error(`invalid_magi_panel: too many members (max ${MAX_MAGI_PANEL_MEMBERS})`);
667
+ }
668
+ const members: MagiPanelMember[] = rawMembers.map((entry, idx) => {
669
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
670
+ throw new Error(`invalid_magi_panel: member[${idx}] must be an object`);
671
+ }
672
+ const m = entry as Record<string, unknown>;
673
+ const provider = typeof m.provider === 'string' ? m.provider.trim() : '';
674
+ if (!provider) {
675
+ throw new Error(`invalid_magi_panel: member[${idx}].provider is required`);
676
+ }
677
+ const nodeId = typeof m.nodeId === 'string' && m.nodeId.trim() ? m.nodeId.trim() : undefined;
678
+ const model = typeof m.model === 'string' && m.model.trim() ? m.model.trim() : undefined;
679
+ const capabilityTags = normalizeCapabilityTags(m.capabilityTags);
680
+ const n = normalizeReplicaCount(m.n);
681
+ return {
682
+ provider,
683
+ ...(nodeId ? { nodeId } : {}),
684
+ ...(model ? { model } : {}),
685
+ ...(capabilityTags ? { capabilityTags } : {}),
686
+ ...(n !== undefined ? { n } : {}),
687
+ };
688
+ });
689
+ const description = typeof raw.description === 'string' && raw.description.trim()
690
+ ? raw.description.trim().slice(0, 200)
691
+ : undefined;
692
+ const defaultN = normalizeReplicaCount(raw.defaultN);
693
+ const defaultKind = normalizeMagiPanelDefaultKind(raw.defaultKind);
694
+ return {
695
+ ...(description ? { description } : {}),
696
+ members,
697
+ ...(defaultN !== undefined ? { defaultN } : {}),
698
+ ...(defaultKind !== undefined ? { defaultKind } : {}),
699
+ // dedupExempt is always meaningful for a MAGI panel (intentional same-prompt
700
+ // fan-out). Persist it true unless the caller explicitly disables it.
701
+ dedupExempt: raw.dedupExempt === false ? false : true,
702
+ };
703
+ }
704
+
705
+ function normalizePanelName(name: unknown): string {
706
+ const trimmed = typeof name === 'string' ? name.trim() : '';
707
+ if (!trimmed) throw new Error('invalid_magi_panel: panel name is required');
708
+ return trimmed.slice(0, 100);
709
+ }
710
+
711
+ /** All configured MAGI panels (machine-local), keyed by name. Empty when none. */
712
+ export function listMagiPanels(): Record<string, MagiPanel> {
713
+ return loadMeshConfig().magiPanels ?? {};
714
+ }
715
+
716
+ /** A single panel by name, or undefined when not configured. */
717
+ export function getMagiPanel(name: string): MagiPanel | undefined {
718
+ const key = typeof name === 'string' ? name.trim() : '';
719
+ if (!key) return undefined;
720
+ return loadMeshConfig().magiPanels?.[key];
721
+ }
722
+
723
+ /**
724
+ * Upsert a named panel into meshes.json. Defaults to refusing to clobber an
725
+ * existing panel (overwrite=false) — mirrors the mesh_init write/overwrite
726
+ * precedent. Returns the normalized, persisted panel.
727
+ */
728
+ export function upsertMagiPanel(
729
+ name: string,
730
+ config: unknown,
731
+ opts: { overwrite?: boolean } = {},
732
+ ): MagiPanel {
733
+ const key = normalizePanelName(name);
734
+ const panel = normalizeMagiPanel(config);
735
+ const stored = loadMeshConfig();
736
+ const panels = stored.magiPanels ?? {};
737
+ if (panels[key] && opts.overwrite !== true) {
738
+ throw new Error(`magi_panel_exists: panel '${key}' already exists — pass overwrite=true to replace it`);
739
+ }
740
+ panels[key] = panel;
741
+ stored.magiPanels = panels;
742
+ saveMeshConfig(stored);
743
+ return panel;
744
+ }
745
+
746
+ /** Remove a named panel. Returns true when a panel was removed. */
747
+ export function removeMagiPanel(name: string): boolean {
748
+ const key = typeof name === 'string' ? name.trim() : '';
749
+ if (!key) return false;
750
+ const stored = loadMeshConfig();
751
+ if (!stored.magiPanels || !stored.magiPanels[key]) return false;
752
+ delete stored.magiPanels[key];
753
+ saveMeshConfig(stored);
754
+ return true;
755
+ }
756
+
757
+ // ─── MAGI kind → panel bindings (MAGI-KIND-PANEL) ─────────
758
+ //
759
+ // Per-task_kind slot lists (machine-local, meshes.json `magiKindPanels`). A bare
760
+ // `mesh_magi_review({task_kind})` resolves its panel exclusively from here — an
761
+ // unconfigured kind is a hard error, never a synthesized fallback. Mirrors the named
762
+ // panel accessors above (normalize / list / get / set / remove).
763
+
764
+ /** The task kinds a kind-panel can be bound to. Unlike a named panel's defaultKind,
765
+ * 'freeform' IS a valid kind-panel key (this is a direct kind→slots binding). */
766
+ const MAGI_KIND_PANEL_KINDS: readonly MagiTaskKind[] = ['claim_audit', 'rca', 'design', 'freeform'];
767
+ const MAX_MAGI_KIND_SLOTS = 24;
768
+
769
+ function normalizeMagiTaskKindKey(raw: unknown): MagiTaskKind {
770
+ const s = typeof raw === 'string' ? raw.trim().toLowerCase() : '';
771
+ if (!(MAGI_KIND_PANEL_KINDS as readonly string[]).includes(s)) {
772
+ throw new Error(`invalid_magi_kind_panel: task_kind must be one of ${MAGI_KIND_PANEL_KINDS.join(' / ')} (got '${s || '(empty)'}')`);
773
+ }
774
+ return s as MagiTaskKind;
775
+ }
776
+
777
+ /**
778
+ * Validate + normalize a kind-panel's slots. Mirrors normalizeMagiPanel's member
779
+ * normalization: provider required per slot, trims strings, drops empties, clamps
780
+ * replica counts, and additionally carries an optional per-slot `model`. Throws on
781
+ * structurally invalid input (empty list / no provider) so the write returns a clear
782
+ * error. Returns the normalized slot array.
783
+ */
784
+ export function normalizeMagiSlots(slots: unknown): MagiSlot[] {
785
+ if (!Array.isArray(slots) || slots.length === 0) {
786
+ throw new Error('invalid_magi_kind_panel: slots must be a non-empty array');
787
+ }
788
+ if (slots.length > MAX_MAGI_KIND_SLOTS) {
789
+ throw new Error(`invalid_magi_kind_panel: too many slots (max ${MAX_MAGI_KIND_SLOTS})`);
790
+ }
791
+ return slots.map((entry, idx) => {
792
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
793
+ throw new Error(`invalid_magi_kind_panel: slot[${idx}] must be an object`);
794
+ }
795
+ const s = entry as Record<string, unknown>;
796
+ const provider = typeof s.provider === 'string' ? s.provider.trim() : '';
797
+ if (!provider) {
798
+ throw new Error(`invalid_magi_kind_panel: slot[${idx}].provider is required`);
799
+ }
800
+ const nodeId = typeof s.nodeId === 'string' && s.nodeId.trim() ? s.nodeId.trim() : undefined;
801
+ const model = typeof s.model === 'string' && s.model.trim() ? s.model.trim() : undefined;
802
+ const capabilityTags = normalizeCapabilityTags(s.capabilityTags);
803
+ const n = normalizeReplicaCount(s.n);
804
+ return {
805
+ provider,
806
+ ...(nodeId ? { nodeId } : {}),
807
+ ...(model ? { model } : {}),
808
+ ...(capabilityTags ? { capabilityTags } : {}),
809
+ ...(n !== undefined ? { n } : {}),
810
+ };
811
+ });
812
+ }
813
+
814
+ /** All configured kind-panels (machine-local), keyed by task_kind. Empty when none. */
815
+ export function listMagiKindPanels(): MagiKindPanelMap {
816
+ return loadMeshConfig().magiKindPanels ?? {};
817
+ }
818
+
819
+ /** The slot list for one task_kind, or undefined when the kind is not configured. */
820
+ export function getMagiKindPanel(kind: string): MagiSlot[] | undefined {
821
+ let key: MagiTaskKind;
822
+ try { key = normalizeMagiTaskKindKey(kind); } catch { return undefined; }
823
+ return loadMeshConfig().magiKindPanels?.[key];
824
+ }
825
+
826
+ /**
827
+ * Upsert the slot list for one task_kind. Unlike named panels this ALWAYS overwrites
828
+ * (a kind has exactly one binding) — the editor pushes the full desired slot set.
829
+ * Returns the normalized, persisted slots.
830
+ */
831
+ export function setMagiKindPanel(kind: string, slots: unknown): MagiSlot[] {
832
+ const key = normalizeMagiTaskKindKey(kind);
833
+ const normalized = normalizeMagiSlots(slots);
834
+ const stored = loadMeshConfig();
835
+ const map = stored.magiKindPanels ?? {};
836
+ map[key] = normalized;
837
+ stored.magiKindPanels = map;
838
+ saveMeshConfig(stored);
839
+ return normalized;
840
+ }
841
+
842
+ /** Remove the binding for one task_kind. Returns true when a binding was removed. */
843
+ export function removeMagiKindPanel(kind: string): boolean {
844
+ let key: MagiTaskKind;
845
+ try { key = normalizeMagiTaskKindKey(kind); } catch { return false; }
846
+ const stored = loadMeshConfig();
847
+ if (!stored.magiKindPanels || !stored.magiKindPanels[key]) return false;
848
+ delete stored.magiKindPanels[key];
849
+ saveMeshConfig(stored);
850
+ return true;
851
+ }