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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +9 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/build-info.d.ts +37 -0
  4. package/dist/chat/source-machine.d.ts +166 -0
  5. package/dist/chat/source-resolver.d.ts +104 -0
  6. package/dist/chat/subscription-updates.d.ts +1 -0
  7. package/dist/cli-adapter-types.d.ts +68 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +220 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
  14. package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
  15. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  16. package/dist/cli-adapters/resolve-executable.d.ts +69 -0
  17. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  18. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  19. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  20. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  21. package/dist/commands/chat-commands-read.d.ts +23 -0
  22. package/dist/commands/chat-commands-scope.d.ts +39 -0
  23. package/dist/commands/chat-commands-shared.d.ts +33 -0
  24. package/dist/commands/chat-commands-write.d.ts +14 -0
  25. package/dist/commands/chat-commands.d.ts +10 -23
  26. package/dist/commands/cli-manager.d.ts +71 -1
  27. package/dist/commands/handler.d.ts +125 -0
  28. package/dist/commands/high-family/index.d.ts +3 -0
  29. package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
  30. package/dist/commands/high-family/mesh-events.d.ts +2 -0
  31. package/dist/commands/high-family/mesh-status.d.ts +2 -0
  32. package/dist/commands/high-family/types.d.ts +64 -0
  33. package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
  34. package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
  35. package/dist/commands/low-family/diagnostics.d.ts +2 -0
  36. package/dist/commands/low-family/index.d.ts +3 -0
  37. package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
  38. package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
  39. package/dist/commands/low-family/notification.d.ts +2 -0
  40. package/dist/commands/low-family/refine-config.d.ts +2 -0
  41. package/dist/commands/low-family/session-host.d.ts +2 -0
  42. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  43. package/dist/commands/low-family/status-meta.d.ts +2 -0
  44. package/dist/commands/low-family/types.d.ts +33 -0
  45. package/dist/commands/med-family/cli-agent.d.ts +2 -0
  46. package/dist/commands/med-family/fast-forward.d.ts +2 -0
  47. package/dist/commands/med-family/ide.d.ts +10 -0
  48. package/dist/commands/med-family/index.d.ts +3 -0
  49. package/dist/commands/med-family/mesh-crud.d.ts +48 -0
  50. package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
  51. package/dist/commands/med-family/mesh-queue.d.ts +2 -0
  52. package/dist/commands/med-family/mesh-restart.d.ts +2 -0
  53. package/dist/commands/med-family/types.d.ts +152 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router-aggregate-status.d.ts +24 -0
  56. package/dist/commands/router-mesh-session-owner.d.ts +59 -0
  57. package/dist/commands/router-refine.d.ts +151 -0
  58. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  59. package/dist/commands/router.d.ts +203 -15
  60. package/dist/commands/upgrade-helper.d.ts +41 -1
  61. package/dist/config/chat-history.d.ts +11 -0
  62. package/dist/config/config.d.ts +19 -0
  63. package/dist/config/mesh-config.d.ts +65 -0
  64. package/dist/config/mesh-json-config.d.ts +199 -0
  65. package/dist/config/registry-resolver.d.ts +54 -0
  66. package/dist/config/repo-settings.d.ts +77 -0
  67. package/dist/config/state-store.d.ts +30 -0
  68. package/dist/daemon/dev-server.d.ts +0 -2
  69. package/dist/detection/cli-detector.d.ts +17 -0
  70. package/dist/detection/ide-detector.d.ts +13 -0
  71. package/dist/detection/win32-ide-version.d.ts +37 -0
  72. package/dist/git/change-impact-config.d.ts +159 -0
  73. package/dist/git/git-commands.d.ts +26 -2
  74. package/dist/git/git-diff.d.ts +6 -0
  75. package/dist/git/git-executor.d.ts +11 -0
  76. package/dist/git/git-status.d.ts +80 -0
  77. package/dist/git/git-types.d.ts +2 -50
  78. package/dist/git/git-worktree.d.ts +71 -1
  79. package/dist/git/index.d.ts +3 -1
  80. package/dist/index.d.ts +70 -17
  81. package/dist/index.js +53532 -19073
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +53283 -18989
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/installer.d.ts +1 -4
  86. package/dist/ipc/local-ipc-server.d.ts +91 -0
  87. package/dist/launch.d.ts +1 -1
  88. package/dist/logging/async-batch-writer.d.ts +10 -0
  89. package/dist/logging/debug-config.d.ts +16 -0
  90. package/dist/logging/log-redactor.d.ts +24 -0
  91. package/dist/logging/log-tail-reader.d.ts +81 -0
  92. package/dist/logging/logger.d.ts +1 -1
  93. package/dist/mesh/contracts.d.ts +256 -0
  94. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  95. package/dist/mesh/coordinator-registry.d.ts +59 -0
  96. package/dist/mesh/mesh-active-work.d.ts +203 -0
  97. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  98. package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
  99. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  100. package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
  101. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  102. package/dist/mesh/mesh-event-forwarding.d.ts +58 -0
  103. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  104. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  105. package/dist/mesh/mesh-events-pending.d.ts +258 -0
  106. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  107. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  108. package/dist/mesh/mesh-events.d.ts +6 -49
  109. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  110. package/dist/mesh/mesh-host-ownership.d.ts +21 -1
  111. package/dist/mesh/mesh-init.d.ts +128 -0
  112. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  113. package/dist/mesh/mesh-ledger.d.ts +139 -1
  114. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  115. package/dist/mesh/mesh-missions.d.ts +281 -0
  116. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  117. package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
  118. package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
  119. package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
  120. package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
  121. package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
  122. package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
  123. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  124. package/dist/mesh/mesh-refine-gates.d.ts +457 -0
  125. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  126. package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
  127. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  128. package/dist/mesh/mesh-routing.d.ts +70 -0
  129. package/dist/mesh/mesh-runtime-store.d.ts +567 -0
  130. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  131. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  132. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  133. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +34 -0
  134. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  135. package/dist/mesh/mesh-work-queue.d.ts +392 -1
  136. package/dist/mesh/preview-freshness.d.ts +28 -0
  137. package/dist/mesh/refine-config.d.ts +97 -0
  138. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  139. package/dist/providers/acp-provider-instance.d.ts +5 -0
  140. package/dist/providers/approval-utils.d.ts +46 -0
  141. package/dist/providers/chat-message-normalization.d.ts +58 -1
  142. package/dist/providers/cli-provider-effect-format.d.ts +30 -0
  143. package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
  144. package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
  145. package/dist/providers/cli-provider-instance-types.d.ts +45 -0
  146. package/dist/providers/cli-provider-instance.d.ts +426 -30
  147. package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
  148. package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
  149. package/dist/providers/contracts.d.ts +196 -6
  150. package/dist/providers/external-sources.d.ts +71 -0
  151. package/dist/providers/manual-attendance.d.ts +79 -0
  152. package/dist/providers/native-history/antigravity-claim-registry.d.ts +39 -0
  153. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  154. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  155. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  156. package/dist/providers/native-history/constants.d.ts +12 -0
  157. package/dist/providers/native-history/dispatcher.d.ts +44 -0
  158. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  159. package/dist/providers/native-history/index.d.ts +13 -0
  160. package/dist/providers/provider-instance-manager.d.ts +30 -0
  161. package/dist/providers/provider-instance.d.ts +31 -1
  162. package/dist/providers/provider-loader.d.ts +42 -5
  163. package/dist/providers/provider-trust.d.ts +31 -0
  164. package/dist/providers/read-chat-contract.d.ts +29 -0
  165. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  166. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  167. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  168. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  169. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  170. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  171. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  172. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  173. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  174. package/dist/providers/sdk/v1/index.d.ts +30 -0
  175. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  176. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  177. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  178. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  179. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  180. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  181. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  182. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  183. package/dist/providers/spec/adapter.d.ts +98 -0
  184. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  185. package/dist/providers/spec/evaluator.d.ts +45 -0
  186. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  187. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  188. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  189. package/dist/providers/spec/fsm-types.d.ts +202 -0
  190. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  191. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  192. package/dist/providers/spec/route.d.ts +4 -0
  193. package/dist/providers/spec/types.d.ts +244 -0
  194. package/dist/providers/status-monitor.d.ts +7 -7
  195. package/dist/providers/transcript-v2.d.ts +176 -0
  196. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  197. package/dist/providers/working-dir.d.ts +17 -0
  198. package/dist/repo-mesh-types.d.ts +616 -12
  199. package/dist/runtime-defaults.d.ts +2 -0
  200. package/dist/session-host/managed-host.d.ts +64 -0
  201. package/dist/session-host/runtime-surface.d.ts +10 -16
  202. package/dist/sessions/registry.d.ts +26 -0
  203. package/dist/shared-types-extra.d.ts +2 -4
  204. package/dist/shared-types.d.ts +110 -55
  205. package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
  206. package/dist/status/normalize.d.ts +1 -1
  207. package/dist/status/normalize.js +1 -0
  208. package/dist/status/normalize.js.map +1 -1
  209. package/dist/status/normalize.mjs +1 -0
  210. package/dist/status/normalize.mjs.map +1 -1
  211. package/dist/status/reporter.d.ts +2 -0
  212. package/dist/status/snapshot.d.ts +27 -0
  213. package/dist/system/hash.d.ts +8 -0
  214. package/dist/system/load-better-sqlite3.d.ts +21 -0
  215. package/dist/types.d.ts +20 -6
  216. package/package.json +11 -4
  217. package/src/agent-stream/poller.ts +2 -3
  218. package/src/agent-stream/provider-adapter.ts +1 -1
  219. package/src/boot/daemon-lifecycle.ts +80 -14
  220. package/src/boot/process-hardening.ts +89 -0
  221. package/src/build-info.ts +73 -0
  222. package/src/chat/source-machine.ts +534 -0
  223. package/src/chat/source-resolver.ts +0 -0
  224. package/src/chat/subscription-updates.ts +20 -1
  225. package/src/cli-adapter-types.d.ts +3 -1
  226. package/src/cli-adapter-types.ts +68 -2
  227. package/src/cli-adapters/cli-script-runner.ts +421 -0
  228. package/src/cli-adapters/cli-state-engine.ts +1282 -0
  229. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  230. package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
  231. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  232. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  233. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  234. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  235. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  236. package/src/cli-adapters/pty-transport.ts +2 -1
  237. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  238. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  239. package/src/cli-adapters/resolve-executable.ts +204 -0
  240. package/src/cli-adapters/session-host-transport.ts +2 -1
  241. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  242. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  243. package/src/cli-adapters/terminal-screen.ts +16 -81
  244. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  245. package/src/commands/chat-commands-read.ts +2788 -0
  246. package/src/commands/chat-commands-scope.ts +54 -0
  247. package/src/commands/chat-commands-shared.ts +114 -0
  248. package/src/commands/chat-commands-write.ts +891 -0
  249. package/src/commands/chat-commands.ts +19 -1841
  250. package/src/commands/cli-manager.d.ts +2 -0
  251. package/src/commands/cli-manager.ts +724 -27
  252. package/src/commands/handler.ts +865 -2
  253. package/src/commands/high-family/index.ts +28 -0
  254. package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
  255. package/src/commands/high-family/mesh-events.ts +102 -0
  256. package/src/commands/high-family/mesh-status.ts +857 -0
  257. package/src/commands/high-family/types.ts +80 -0
  258. package/src/commands/low-family/coordinator-prompt.ts +125 -0
  259. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  260. package/src/commands/low-family/diagnostics.ts +57 -0
  261. package/src/commands/low-family/index.ts +37 -0
  262. package/src/commands/low-family/mesh-ledger.ts +62 -0
  263. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  264. package/src/commands/low-family/notification.ts +116 -0
  265. package/src/commands/low-family/refine-config.ts +106 -0
  266. package/src/commands/low-family/session-host.ts +282 -0
  267. package/src/commands/low-family/spec-providerdev.ts +217 -0
  268. package/src/commands/low-family/status-meta.ts +112 -0
  269. package/src/commands/low-family/types.ts +39 -0
  270. package/src/commands/med-family/cli-agent.ts +270 -0
  271. package/src/commands/med-family/fast-forward.ts +230 -0
  272. package/src/commands/med-family/ide.ts +163 -0
  273. package/src/commands/med-family/index.ts +37 -0
  274. package/src/commands/med-family/mesh-crud.ts +1268 -0
  275. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  276. package/src/commands/med-family/mesh-queue.ts +167 -0
  277. package/src/commands/med-family/mesh-restart.ts +92 -0
  278. package/src/commands/med-family/types.ts +153 -0
  279. package/src/commands/mesh-coordinator.ts +334 -124
  280. package/src/commands/router-aggregate-status.ts +209 -0
  281. package/src/commands/router-mesh-session-owner.ts +114 -0
  282. package/src/commands/router-refine.ts +1794 -0
  283. package/src/commands/router-worktree-cleanup.ts +870 -0
  284. package/src/commands/router.ts +567 -4149
  285. package/src/commands/stream-commands.ts +8 -0
  286. package/src/commands/upgrade-helper.ts +310 -45
  287. package/src/config/chat-history.ts +517 -24
  288. package/src/config/config.ts +30 -0
  289. package/src/config/mesh-config.ts +300 -24
  290. package/src/config/mesh-json-config.ts +376 -0
  291. package/src/config/recent-activity.ts +8 -2
  292. package/src/config/registry-resolver.ts +100 -0
  293. package/src/config/repo-settings.ts +111 -0
  294. package/src/config/state-store.ts +55 -0
  295. package/src/daemon/dev-auto-implement.ts +3 -2
  296. package/src/daemon/dev-cli-debug.ts +10 -1
  297. package/src/daemon/dev-server.ts +0 -541
  298. package/src/detection/cli-detector.ts +94 -9
  299. package/src/detection/ide-detector.ts +55 -16
  300. package/src/detection/win32-ide-version.ts +106 -0
  301. package/src/git/change-impact-config.ts +354 -0
  302. package/src/git/git-commands.ts +112 -16
  303. package/src/git/git-diff.ts +81 -11
  304. package/src/git/git-executor.ts +12 -0
  305. package/src/git/git-status.ts +822 -48
  306. package/src/git/git-types.ts +14 -62
  307. package/src/git/git-worktree.ts +261 -4
  308. package/src/git/index.ts +17 -0
  309. package/src/index.ts +190 -13
  310. package/src/installer.d.ts +1 -1
  311. package/src/installer.ts +8 -6
  312. package/src/ipc/local-ipc-server.ts +278 -0
  313. package/src/launch.d.ts +1 -1
  314. package/src/launch.ts +37 -28
  315. package/src/logging/async-batch-writer.ts +55 -0
  316. package/src/logging/command-log.ts +7 -5
  317. package/src/logging/debug-config.ts +25 -0
  318. package/src/logging/debug-trace.ts +7 -2
  319. package/src/logging/log-redactor.ts +100 -0
  320. package/src/logging/log-tail-reader.ts +341 -0
  321. package/src/logging/logger.ts +14 -7
  322. package/src/mesh/contracts.ts +510 -0
  323. package/src/mesh/coordinator-prompt.ts +627 -34
  324. package/src/mesh/coordinator-registry.ts +121 -0
  325. package/src/mesh/mesh-active-work.ts +706 -0
  326. package/src/mesh/mesh-clone-grace.ts +68 -0
  327. package/src/mesh/mesh-completion-synthesis.ts +416 -0
  328. package/src/mesh/mesh-coordinator-config.ts +97 -0
  329. package/src/mesh/mesh-delivery-policy.ts +284 -0
  330. package/src/mesh/mesh-event-classify.ts +78 -0
  331. package/src/mesh/mesh-event-forwarding.ts +2030 -0
  332. package/src/mesh/mesh-event-trace.ts +67 -0
  333. package/src/mesh/mesh-events-coordinator.ts +32 -0
  334. package/src/mesh/mesh-events-pending.ts +1548 -0
  335. package/src/mesh/mesh-events-stale.ts +452 -0
  336. package/src/mesh/mesh-events-utils.ts +443 -0
  337. package/src/mesh/mesh-events.ts +43 -1035
  338. package/src/mesh/mesh-fast-forward.ts +856 -0
  339. package/src/mesh/mesh-host-ownership.ts +41 -3
  340. package/src/mesh/mesh-init.ts +350 -0
  341. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  342. package/src/mesh/mesh-ledger.ts +897 -102
  343. package/src/mesh/mesh-magi-status.ts +223 -0
  344. package/src/mesh/mesh-missions.ts +695 -0
  345. package/src/mesh/mesh-node-identity.ts +2065 -0
  346. package/src/mesh/mesh-queue-assignment.ts +2498 -0
  347. package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
  348. package/src/mesh/mesh-reconcile-config.ts +66 -0
  349. package/src/mesh/mesh-reconcile-identity.ts +103 -0
  350. package/src/mesh/mesh-reconcile-loop.ts +1696 -0
  351. package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
  352. package/src/mesh/mesh-refine-batch.ts +205 -0
  353. package/src/mesh/mesh-refine-gates.ts +1792 -0
  354. package/src/mesh/mesh-refine-status.ts +231 -0
  355. package/src/mesh/mesh-remote-event-pull.ts +279 -0
  356. package/src/mesh/mesh-review-inbox.ts +308 -0
  357. package/src/mesh/mesh-routing.ts +291 -0
  358. package/src/mesh/mesh-runtime-store.ts +2292 -0
  359. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  360. package/src/mesh/mesh-task-inflight.ts +70 -0
  361. package/src/mesh/mesh-task-stats.ts +161 -0
  362. package/src/mesh/mesh-unresolved-forward-outbox.ts +215 -0
  363. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  364. package/src/mesh/mesh-work-queue.ts +1489 -145
  365. package/src/mesh/preview-freshness.ts +163 -0
  366. package/src/mesh/refine-config.ts +129 -12
  367. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  368. package/src/providers/acp-provider-instance.ts +43 -10
  369. package/src/providers/approval-utils.d.ts +5 -0
  370. package/src/providers/approval-utils.ts +100 -6
  371. package/src/providers/chat-message-normalization.ts +126 -4
  372. package/src/providers/cli-provider-effect-format.ts +53 -0
  373. package/src/providers/cli-provider-history-dedup.ts +75 -0
  374. package/src/providers/cli-provider-input-prompt.ts +133 -0
  375. package/src/providers/cli-provider-instance-types.ts +131 -0
  376. package/src/providers/cli-provider-instance.ts +2771 -499
  377. package/src/providers/cli-provider-status-helpers.ts +123 -0
  378. package/src/providers/cli-provider-transcript-merge.ts +114 -0
  379. package/src/providers/contracts.d.ts +55 -0
  380. package/src/providers/contracts.ts +207 -6
  381. package/src/providers/extension-provider-instance.ts +12 -7
  382. package/src/providers/external-sources.ts +218 -0
  383. package/src/providers/ide-provider-instance.ts +35 -12
  384. package/src/providers/manual-attendance.ts +105 -0
  385. package/src/providers/native-history/antigravity-claim-registry.ts +138 -0
  386. package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -0
  387. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  388. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  389. package/src/providers/native-history/constants.ts +19 -0
  390. package/src/providers/native-history/dispatcher.ts +617 -0
  391. package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
  392. package/src/providers/native-history/index.ts +30 -0
  393. package/src/providers/provider-instance-manager.ts +71 -0
  394. package/src/providers/provider-instance.ts +24 -1
  395. package/src/providers/provider-loader.ts +700 -55
  396. package/src/providers/provider-schema.ts +93 -14
  397. package/src/providers/provider-trust.ts +114 -0
  398. package/src/providers/read-chat-contract.ts +76 -16
  399. package/src/providers/sdk/README.md +49 -0
  400. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  401. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  402. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  403. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  404. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  405. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  406. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  407. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  408. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  409. package/src/providers/sdk/v1/index.ts +152 -0
  410. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  411. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  412. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  413. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +538 -0
  414. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  415. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  416. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  417. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  418. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  419. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  420. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  421. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  422. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  423. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  424. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  425. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  426. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  427. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  428. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  429. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  430. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  431. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  432. package/src/providers/sdk/v1/validators/index.ts +19 -0
  433. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  434. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  435. package/src/providers/spec/adapter.ts +246 -0
  436. package/src/providers/spec/cli-adapter.ts +1064 -0
  437. package/src/providers/spec/evaluator.ts +407 -0
  438. package/src/providers/spec/fsm-driver.ts +1528 -0
  439. package/src/providers/spec/fsm-evaluator.ts +290 -0
  440. package/src/providers/spec/fsm-loader.ts +128 -0
  441. package/src/providers/spec/fsm-types.ts +301 -0
  442. package/src/providers/spec/native-history-executor.ts +1241 -0
  443. package/src/providers/spec/pre-launch-trust.ts +104 -0
  444. package/src/providers/spec/route.ts +51 -0
  445. package/src/providers/spec/types.ts +284 -0
  446. package/src/providers/status-monitor.d.ts +7 -7
  447. package/src/providers/status-monitor.ts +37 -22
  448. package/src/providers/transcript-v2.ts +567 -0
  449. package/src/providers/types/interactive-prompt.ts +536 -0
  450. package/src/providers/version-archive.ts +64 -24
  451. package/src/providers/working-dir.ts +23 -0
  452. package/src/repo-mesh-types.ts +861 -14
  453. package/src/runtime-defaults.ts +39 -0
  454. package/src/session-host/managed-host.ts +218 -0
  455. package/src/session-host/runtime-surface.ts +20 -80
  456. package/src/sessions/registry.ts +44 -0
  457. package/src/shared-types-extra.ts +2 -4
  458. package/src/shared-types.d.ts +8 -0
  459. package/src/shared-types.ts +148 -55
  460. package/src/status/builders.ts +69 -6
  461. package/src/status/chat-tail-hot-sessions.ts +117 -2
  462. package/src/status/normalize.ts +2 -0
  463. package/src/status/reporter.ts +19 -1
  464. package/src/status/snapshot.ts +100 -27
  465. package/src/system/hash.ts +23 -0
  466. package/src/system/host-memory.ts +29 -12
  467. package/src/system/load-better-sqlite3.ts +68 -0
  468. package/src/types.ts +26 -6
  469. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  470. package/dist/mesh/mesh-sync.d.ts +0 -53
  471. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  472. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  473. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,290 @@
1
+ /**
2
+ * FSM evaluator — pure transition evaluation for adhdev:cli/spec@4.
3
+ *
4
+ * Given the current state, the screen, and a clock context (when the current
5
+ * state was entered, when each cursor_above region last changed), decides
6
+ * which outgoing transition fires — and records WHY every transition did or
7
+ * did not fire. That "why" trace is the whole point: it is what makes the FSM
8
+ * debuggable from the daemon API without guessing.
9
+ *
10
+ * Screen-content leaves (regex / changed) are delegated to the shared v3
11
+ * condition evaluator. Time leaves (elapsed_ms / stable_ms) are evaluated here
12
+ * against the clock context the driver passes in. No wall-clock reads happen
13
+ * in this file — the driver owns `now` so the function stays pure & testable.
14
+ */
15
+ 'use strict';
16
+
17
+ import type { Condition, SectionDef } from './types.js';
18
+ import {
19
+ resolveSections, evaluateCondition, sectionText, type ResolvedSection, type TraceEntry,
20
+ } from './evaluator.js';
21
+ import {
22
+ type CliSpecV4, type FsmCondition, type FsmTransition,
23
+ outgoingTransitions, stateById,
24
+ } from './fsm-types.js';
25
+
26
+ export interface FsmClock {
27
+ /** Wall-clock now (ms). Passed in so the evaluator stays pure. */
28
+ now: number;
29
+ /** When the current state was entered (ms). */
30
+ stateEnteredAt: number;
31
+ /** Last-changed timestamp per stable region. Numeric key = cursor_above
32
+ * value (0 / undefined → whole-screen, keyed as -1). String key =
33
+ * `section:<id>` for a section-scoped stable region. Missing key means
34
+ * "never observed changing" → treated as stable since stateEnteredAt. */
35
+ regionLastChangedAt: Map<number | string, number>;
36
+ }
37
+
38
+ /** Per-condition evaluation detail — the debugging payload. */
39
+ export interface CondResult {
40
+ kind: 'regex' | 'changed' | 'elapsed' | 'stable' | 'all' | 'any' | 'not';
41
+ result: boolean;
42
+ detail: string;
43
+ /** Remaining ms until a time-based condition would flip to true. 0 if
44
+ * already true or not applicable. Lets the UI show a countdown. */
45
+ remainingMs?: number;
46
+ /** Debug-only: the actual substring a TRUE regex condition matched, so the
47
+ * snapshot shows WHAT text the rule fired on — not just which regex. Never
48
+ * read by the FSM; purely for the Spec Debug Snapshot. */
49
+ matchedText?: string;
50
+ children?: CondResult[];
51
+ }
52
+
53
+ /** One evaluated transition with its full reasoning. */
54
+ export interface TransitionEval {
55
+ to: string;
56
+ label: string;
57
+ /** Did the `from` clause include the current state? (Always true for the
58
+ * transitions we return — kept for completeness.) */
59
+ eligible: boolean;
60
+ /** min_hold_ms guard satisfied? */
61
+ holdSatisfied: boolean;
62
+ holdRemainingMs: number;
63
+ /** Guard condition result (true if no `when`). */
64
+ condResult: boolean;
65
+ cond?: CondResult;
66
+ /** Overall: would this transition fire? */
67
+ fires: boolean;
68
+ priority: number;
69
+ }
70
+
71
+ export interface FsmEvaluation {
72
+ /** Sections resolved from the screen (shared with v3 shape). */
73
+ sections: ResolvedSection[];
74
+ /** Every outgoing transition from the current state, priority-ordered,
75
+ * each annotated with why it fired or didn't. */
76
+ transitions: TransitionEval[];
77
+ /** The transition that fires (first in priority order with fires===true),
78
+ * or null to stay in the current state. */
79
+ fired: TransitionEval | null;
80
+ /** v3-compatible trace lines for the legacy inspector. */
81
+ trace: TraceEntry[];
82
+ }
83
+
84
+ const WHOLE_SCREEN = -1;
85
+
86
+ /** The `regionLastChangedAt` key for a stable condition. The key must capture
87
+ * everything that makes two stable clauses watch a DIFFERENT change signal:
88
+ * the geometric region (`section` wins over `cursor_above`, else whole-screen)
89
+ * AND the `ignore_lines` filter (two clauses on the same region but different
90
+ * ignore patterns see different "did it change" answers). Kept in one place so
91
+ * the driver (which populates the map) and the evaluator (which reads it)
92
+ * agree on the key.
93
+ *
94
+ * Bare whole-screen with no ignore filter keeps its historical numeric key -1
95
+ * so existing callers/tests that seed `regionLastChangedAt` with [-1, ...]
96
+ * keep working unchanged. */
97
+ export function stableRegionKey(cond: { section?: string; cursor_above?: number; ignore_lines?: string }): number | string {
98
+ const region = cond.section
99
+ ? `section:${cond.section}`
100
+ : (cond.cursor_above && cond.cursor_above > 0 ? cond.cursor_above : WHOLE_SCREEN);
101
+ if (!cond.ignore_lines) return region;
102
+ return `${region}#ignore:${cond.ignore_lines}`;
103
+ }
104
+
105
+ function isRegex(c: FsmCondition): c is import('./types.js').RegexCondition {
106
+ return 'matches' in c;
107
+ }
108
+ function isChanged(c: FsmCondition): c is import('./types.js').ChangedCondition {
109
+ return 'cursor_above' in c && 'changed' in c;
110
+ }
111
+ function isElapsed(c: FsmCondition): c is import('./fsm-types.js').ElapsedCondition {
112
+ return 'elapsed_ms' in c;
113
+ }
114
+ function isStable(c: FsmCondition): c is import('./fsm-types.js').StableCondition {
115
+ return 'stable_ms' in c;
116
+ }
117
+ function isAll(c: FsmCondition): c is import('./fsm-types.js').FsmAllCondition {
118
+ return 'all' in c;
119
+ }
120
+ function isAny(c: FsmCondition): c is import('./fsm-types.js').FsmAnyCondition {
121
+ return 'any' in c;
122
+ }
123
+ function isNot(c: FsmCondition): c is import('./fsm-types.js').FsmNotCondition {
124
+ return 'not' in c;
125
+ }
126
+
127
+ /**
128
+ * Evaluate a single FSM condition into a {result, detail, remainingMs, children}.
129
+ * Recurses through all/any/not; defers regex/changed to the shared evaluator;
130
+ * handles elapsed_ms/stable_ms against the clock.
131
+ */
132
+ function evalCond(
133
+ cond: FsmCondition,
134
+ sections: ResolvedSection[],
135
+ fullScreen: string,
136
+ cursor: { row: number; col: number } | undefined,
137
+ prevLines: string[] | undefined,
138
+ clock: FsmClock,
139
+ legacyTrace: TraceEntry[],
140
+ stateId: string,
141
+ ): CondResult {
142
+ if (isAll(cond)) {
143
+ const children = cond.all.map(c =>
144
+ evalCond(c, sections, fullScreen, cursor, prevLines, clock, legacyTrace, stateId));
145
+ const result = children.every(c => c.result);
146
+ const remainingMs = result ? 0 : Math.max(0, ...children.filter(c => !c.result).map(c => c.remainingMs ?? 0));
147
+ return { kind: 'all', result, detail: `all(${children.length})`, remainingMs, children };
148
+ }
149
+ if (isAny(cond)) {
150
+ const children = cond.any.map(c =>
151
+ evalCond(c, sections, fullScreen, cursor, prevLines, clock, legacyTrace, stateId));
152
+ const result = children.some(c => c.result);
153
+ // remaining = the soonest child that could flip true
154
+ const pending = children.filter(c => !c.result).map(c => c.remainingMs ?? Infinity);
155
+ const remainingMs = result ? 0 : (pending.length ? Math.min(...pending) : 0);
156
+ return { kind: 'any', result, detail: `any(${children.length})`, remainingMs: Number.isFinite(remainingMs) ? remainingMs : 0, children };
157
+ }
158
+ if (isNot(cond)) {
159
+ const child = evalCond(cond.not, sections, fullScreen, cursor, prevLines, clock, legacyTrace, stateId);
160
+ return { kind: 'not', result: !child.result, detail: `not`, remainingMs: 0, children: [child] };
161
+ }
162
+ if (isElapsed(cond)) {
163
+ const age = clock.now - clock.stateEnteredAt;
164
+ const result = age >= cond.elapsed_ms;
165
+ const remainingMs = result ? 0 : cond.elapsed_ms - age;
166
+ return { kind: 'elapsed', result, detail: `elapsed ${age}ms / ${cond.elapsed_ms}ms`, remainingMs };
167
+ }
168
+ if (isStable(cond)) {
169
+ const key = stableRegionKey(cond);
170
+ // If we never saw the region change, treat it as stable since the
171
+ // state was entered (conservative — avoids a premature "stable" on
172
+ // the very first frame).
173
+ const lastChanged = clock.regionLastChangedAt.get(key) ?? clock.stateEnteredAt;
174
+ const stableFor = clock.now - lastChanged;
175
+ const result = stableFor >= cond.stable_ms;
176
+ const remainingMs = result ? 0 : cond.stable_ms - stableFor;
177
+ const where = cond.section ? `section=${cond.section}`
178
+ : cond.cursor_above && cond.cursor_above > 0 ? `cursor_above=${cond.cursor_above}` : 'screen';
179
+ const ign = cond.ignore_lines ? ' (ignore_lines)' : '';
180
+ return { kind: 'stable', result, detail: `stable ${where}${ign} ${stableFor}ms / ${cond.stable_ms}ms`, remainingMs };
181
+ }
182
+ // regex / changed → shared evaluator (operates on v3 Condition shape)
183
+ if (isRegex(cond) || isChanged(cond)) {
184
+ const result = evaluateCondition(cond as Condition, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
185
+ const kind = isRegex(cond) ? 'regex' : 'changed';
186
+ const detail = isRegex(cond)
187
+ ? `${(cond as any).section ?? '*'}~/${(cond as any).matches}/`
188
+ : `cursor_above=${(cond as any).cursor_above} changed=${(cond as any).changed}`;
189
+ // Debug-only: when a regex condition is TRUE, also capture the substring
190
+ // it matched so the snapshot can show the exact text the rule fired on.
191
+ // This re-runs the regex (read-only) and CANNOT change `result` above —
192
+ // the FSM decision is still entirely owned by evaluateCondition().
193
+ let matchedText: string | undefined;
194
+ if (result && isRegex(cond)) {
195
+ try {
196
+ const hay = sectionText(sections, (cond as any).section, fullScreen);
197
+ const re = new RegExp((cond as any).matches, (cond as any).flags ?? 'i');
198
+ const m = re.exec(hay);
199
+ if (m && m[0]) matchedText = m[0].replace(/\s+/g, ' ').trim().slice(0, 160);
200
+ } catch { /* capture is best-effort; never affects result */ }
201
+ }
202
+ return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
203
+ }
204
+ return { kind: 'all', result: false, detail: 'unknown condition' };
205
+ }
206
+
207
+ function fromLabel(t: FsmTransition): string {
208
+ const from = Array.isArray(t.from) ? t.from.join('|') : t.from;
209
+ return t.label ?? `${from}→${t.to}`;
210
+ }
211
+
212
+ /**
213
+ * Evaluate the FSM: given the current state id and screen, return every
214
+ * outgoing transition annotated with why it fires/doesn't, plus the one that
215
+ * fires (if any).
216
+ */
217
+ export function evaluateFsm(
218
+ spec: CliSpecV4,
219
+ currentStateId: string,
220
+ screenText: string,
221
+ cursor: { row: number; col: number } | undefined,
222
+ prevLines: string[] | undefined,
223
+ clock: FsmClock,
224
+ ): FsmEvaluation {
225
+ const legacyTrace: TraceEntry[] = [];
226
+ const lines = screenText.split('\n').map(l => l.endsWith('\r') ? l.slice(0, -1) : l);
227
+ const cleanScreen = lines.join('\n');
228
+ const sections = resolveSections(spec.sections ?? {}, lines);
229
+
230
+ const outgoing = outgoingTransitions(spec, currentStateId);
231
+ const transitions: TransitionEval[] = [];
232
+ let fired: TransitionEval | null = null;
233
+
234
+ for (const t of outgoing) {
235
+ const holdMs = t.min_hold_ms ?? 0;
236
+ const heldFor = clock.now - clock.stateEnteredAt;
237
+ const holdSatisfied = heldFor >= holdMs;
238
+ const holdRemainingMs = holdSatisfied ? 0 : holdMs - heldFor;
239
+
240
+ let cond: CondResult | undefined;
241
+ let condResult = true;
242
+ if (t.when) {
243
+ cond = evalCond(t.when, sections, cleanScreen, cursor, prevLines, clock, legacyTrace, `${currentStateId}→${t.to}`);
244
+ condResult = cond.result;
245
+ }
246
+
247
+ const fires = holdSatisfied && condResult;
248
+ const te: TransitionEval = {
249
+ to: t.to,
250
+ label: fromLabel(t),
251
+ eligible: true,
252
+ holdSatisfied,
253
+ holdRemainingMs,
254
+ condResult,
255
+ cond,
256
+ fires,
257
+ priority: t.priority ?? 0,
258
+ };
259
+ transitions.push(te);
260
+ if (fires && !fired) fired = te;
261
+ }
262
+
263
+ // Validate destination exists (defensive — loader should catch this).
264
+ if (fired && !stateById(spec, fired.to)) {
265
+ legacyTrace.push({ kind: 'state_skip', text: `transition target ${fired.to} not found` });
266
+ fired = null;
267
+ }
268
+
269
+ return { sections, transitions, fired, trace: legacyTrace };
270
+ }
271
+
272
+ /**
273
+ * Evaluate a single condition against a screen + section map — for the spec
274
+ * editor's live preview ("does this regex match the current screen right
275
+ * now?"). Time leaves (elapsed_ms/stable_ms) are evaluated against a synthetic
276
+ * clock where the state was just entered, so they report their countdown
277
+ * rather than firing; the preview is about screen-content match, not timing.
278
+ */
279
+ export function evaluateConditionPreview(
280
+ cond: FsmCondition,
281
+ sections: Record<string, SectionDef> | undefined,
282
+ screenText: string,
283
+ cursor?: { row: number; col: number },
284
+ ): CondResult {
285
+ const lines = screenText.split('\n').map(l => l.endsWith('\r') ? l.slice(0, -1) : l);
286
+ const cleanScreen = lines.join('\n');
287
+ const resolved = resolveSections(sections ?? {}, lines);
288
+ const clock: FsmClock = { now: 0, stateEnteredAt: 0, regionLastChangedAt: new Map() };
289
+ return evalCond(cond, resolved, cleanScreen, cursor, undefined, clock, [], 'preview');
290
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * FSM spec (adhdev:cli/spec@4) loader + validator.
3
+ *
4
+ * Validation is intentionally code-based (not AJV) so a spec authored live in
5
+ * the debug panel gets precise, human-readable errors ("transition[2].to
6
+ * references unknown state 'budy'") instead of a JSON-schema path. Every error
7
+ * is something a spec author can act on without reading the engine.
8
+ */
9
+ 'use strict';
10
+
11
+ import * as fs from 'node:fs';
12
+ import { type CliSpecV4, type FsmCondition, isV4Spec } from './fsm-types.js';
13
+
14
+ export interface FsmLoadOk { ok: true; spec: CliSpecV4; sourcePath: string; }
15
+ export interface FsmLoadErr { ok: false; errors: string[]; sourcePath: string; }
16
+
17
+ export function loadFsmSpec(sourcePath: string): FsmLoadOk | FsmLoadErr {
18
+ let raw: unknown;
19
+ try {
20
+ raw = JSON.parse(fs.readFileSync(sourcePath, 'utf8'));
21
+ } catch (err) {
22
+ return { ok: false, errors: [`Failed to read/parse spec: ${(err as Error).message}`], sourcePath };
23
+ }
24
+ const errors = validateFsmSpec(raw);
25
+ if (errors.length) return { ok: false, errors, sourcePath };
26
+ return { ok: true, spec: raw as CliSpecV4, sourcePath };
27
+ }
28
+
29
+ /** Pure validator — usable from a "validate before save" API in the panel. */
30
+ export function validateFsmSpec(raw: unknown): string[] {
31
+ const errs: string[] = [];
32
+ if (!isV4Spec(raw)) return ['$schema must be "adhdev:cli/spec@4"'];
33
+ const spec = raw as CliSpecV4;
34
+
35
+ if (!spec.id) errs.push('id is required');
36
+ if (!spec.binary) errs.push('binary is required');
37
+ if (!spec.send_message?.submit_key) errs.push('send_message.submit_key is required');
38
+
39
+ if (spec.pre_launch_trust !== undefined) {
40
+ const t = spec.pre_launch_trust as { settings_path?: unknown; key?: unknown };
41
+ if (!t || typeof t !== 'object' || Array.isArray(t)) {
42
+ errs.push('pre_launch_trust must be an object');
43
+ } else {
44
+ if (typeof t.settings_path !== 'string' || !t.settings_path) errs.push('pre_launch_trust.settings_path is required');
45
+ if (typeof t.key !== 'string' || !t.key) errs.push('pre_launch_trust.key is required');
46
+ }
47
+ }
48
+
49
+ if (spec.refocus_when_stalled_ms !== undefined) {
50
+ if (typeof spec.refocus_when_stalled_ms !== 'number' || !(spec.refocus_when_stalled_ms > 0)) {
51
+ errs.push('refocus_when_stalled_ms must be a positive number');
52
+ } else if (!Array.isArray(spec.send_on_spawn) || spec.send_on_spawn.length === 0) {
53
+ errs.push('refocus_when_stalled_ms requires send_on_spawn (the wake sequence to re-inject)');
54
+ }
55
+ }
56
+
57
+ if (!Array.isArray(spec.states) || spec.states.length === 0) {
58
+ errs.push('states[] must be a non-empty array');
59
+ return errs;
60
+ }
61
+ if (!Array.isArray(spec.transitions)) {
62
+ errs.push('transitions[] must be an array');
63
+ return errs;
64
+ }
65
+
66
+ const ids = new Set<string>();
67
+ let initialCount = 0;
68
+ for (const [i, s] of spec.states.entries()) {
69
+ if (!s.id) { errs.push(`states[${i}].id is required`); continue; }
70
+ if (ids.has(s.id)) errs.push(`states[${i}].id "${s.id}" is duplicated`);
71
+ ids.add(s.id);
72
+ if (!s.label) errs.push(`states[${i}].label is required`);
73
+ if (s.initial) initialCount += 1;
74
+ if (s.status && !['idle', 'generating', 'approval'].includes(s.status)) {
75
+ errs.push(`states[${i}].status "${s.status}" must be idle|generating|approval`);
76
+ }
77
+ }
78
+ if (initialCount === 0) errs.push('exactly one state must have initial:true (none found)');
79
+ if (initialCount > 1) errs.push(`exactly one state must have initial:true (${initialCount} found)`);
80
+
81
+ const sectionIds = new Set(Object.keys(spec.sections ?? {}));
82
+ for (const [i, t] of spec.transitions.entries()) {
83
+ const froms = t.from === '*' ? [] : (Array.isArray(t.from) ? t.from : [t.from]);
84
+ for (const f of froms) {
85
+ if (!ids.has(f)) errs.push(`transitions[${i}].from references unknown state "${f}"`);
86
+ }
87
+ if (t.from !== '*' && froms.length === 0) errs.push(`transitions[${i}].from is required`);
88
+ if (!t.to) errs.push(`transitions[${i}].to is required`);
89
+ else if (!ids.has(t.to)) errs.push(`transitions[${i}].to references unknown state "${t.to}"`);
90
+ if (t.when) errs.push(...validateCondition(t.when, sectionIds, `transitions[${i}].when`));
91
+ }
92
+
93
+ // Section refs in state.extract
94
+ for (const [i, s] of spec.states.entries()) {
95
+ const sec = s.extract?.title?.section;
96
+ if (sec && !sectionIds.has(sec)) errs.push(`states[${i}].extract.title.section "${sec}" unknown`);
97
+ const bsec = s.extract?.buttons?.section;
98
+ if (bsec && !sectionIds.has(bsec)) errs.push(`states[${i}].extract.buttons.section "${bsec}" unknown`);
99
+ }
100
+
101
+ return errs;
102
+ }
103
+
104
+ function validateCondition(c: FsmCondition, sectionIds: Set<string>, path: string): string[] {
105
+ const errs: string[] = [];
106
+ const w = c as any;
107
+ if ('all' in w) { w.all.forEach((x: FsmCondition, i: number) => errs.push(...validateCondition(x, sectionIds, `${path}.all[${i}]`))); return errs; }
108
+ if ('any' in w) { w.any.forEach((x: FsmCondition, i: number) => errs.push(...validateCondition(x, sectionIds, `${path}.any[${i}]`))); return errs; }
109
+ if ('not' in w) { errs.push(...validateCondition(w.not, sectionIds, `${path}.not`)); return errs; }
110
+ if ('matches' in w) {
111
+ if (w.section && !sectionIds.has(w.section)) errs.push(`${path}.section "${w.section}" unknown`);
112
+ try { new RegExp(w.matches, w.flags ?? 'i'); } catch (e) { errs.push(`${path}.matches invalid regex: ${(e as Error).message}`); }
113
+ return errs;
114
+ }
115
+ if ('cursor_above' in w && 'changed' in w) return errs;
116
+ if ('elapsed_ms' in w) { if (typeof w.elapsed_ms !== 'number') errs.push(`${path}.elapsed_ms must be a number`); return errs; }
117
+ if ('stable_ms' in w) {
118
+ if (typeof w.stable_ms !== 'number') errs.push(`${path}.stable_ms must be a number`);
119
+ if (w.section && !sectionIds.has(w.section)) errs.push(`${path}.section "${w.section}" unknown`);
120
+ if (w.ignore_lines !== undefined) {
121
+ if (typeof w.ignore_lines !== 'string') errs.push(`${path}.ignore_lines must be a string`);
122
+ else try { new RegExp(w.ignore_lines, 'm'); } catch (e) { errs.push(`${path}.ignore_lines invalid regex: ${(e as Error).message}`); }
123
+ }
124
+ return errs;
125
+ }
126
+ errs.push(`${path} is not a recognized condition`);
127
+ return errs;
128
+ }