@adhdev/daemon-core 0.9.82-rc.43 → 0.9.82-rc.430

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 (425) 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 +15 -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 +60 -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 +142 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router.d.ts +276 -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 +100 -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 +11 -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 +64 -14
  74. package/dist/index.js +49391 -19228
  75. package/dist/index.js.map +1 -1
  76. package/dist/index.mjs +48574 -18570
  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 +9 -0
  102. package/dist/mesh/mesh-init.d.ts +86 -0
  103. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  104. package/dist/mesh/mesh-ledger.d.ts +77 -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 +289 -0
  108. package/dist/mesh/mesh-queue-assignment.d.ts +113 -0
  109. package/dist/mesh/mesh-reconcile-loop.d.ts +65 -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 +290 -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 +31 -1
  128. package/dist/providers/cli-provider-instance.d.ts +221 -3
  129. package/dist/providers/contracts.d.ts +139 -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 +100 -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 +91 -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 +422 -0
  166. package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
  167. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  168. package/dist/providers/spec/fsm-types.d.ts +174 -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 +501 -13
  178. package/dist/runtime-defaults.d.ts +2 -0
  179. package/dist/sessions/registry.d.ts +6 -0
  180. package/dist/shared-types-extra.d.ts +2 -4
  181. package/dist/shared-types.d.ts +59 -2
  182. package/dist/status/normalize.d.ts +1 -1
  183. package/dist/status/normalize.js +1 -0
  184. package/dist/status/normalize.js.map +1 -1
  185. package/dist/status/normalize.mjs +1 -0
  186. package/dist/status/normalize.mjs.map +1 -1
  187. package/dist/status/reporter.d.ts +2 -0
  188. package/dist/status/snapshot.d.ts +26 -0
  189. package/dist/system/hash.d.ts +8 -0
  190. package/dist/system/load-better-sqlite3.d.ts +21 -0
  191. package/dist/types.d.ts +5 -0
  192. package/package.json +7 -3
  193. package/src/agent-stream/poller.ts +2 -3
  194. package/src/agent-stream/provider-adapter.ts +1 -1
  195. package/src/boot/daemon-lifecycle.ts +63 -12
  196. package/src/boot/process-hardening.ts +89 -0
  197. package/src/build-info.ts +73 -0
  198. package/src/chat/source-machine.ts +534 -0
  199. package/src/chat/source-resolver.ts +0 -0
  200. package/src/chat/subscription-updates.ts +20 -1
  201. package/src/cli-adapter-types.d.ts +3 -1
  202. package/src/cli-adapter-types.ts +68 -2
  203. package/src/cli-adapters/cli-script-runner.ts +421 -0
  204. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  205. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  206. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  207. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  208. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  209. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  210. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  211. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  212. package/src/cli-adapters/pty-transport.ts +2 -1
  213. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  214. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  215. package/src/cli-adapters/resolve-executable.ts +204 -0
  216. package/src/cli-adapters/session-host-transport.ts +2 -1
  217. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  218. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  219. package/src/cli-adapters/terminal-screen.ts +16 -81
  220. package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
  221. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  222. package/src/commands/chat-commands-read.ts +2327 -0
  223. package/src/commands/chat-commands-scope.ts +54 -0
  224. package/src/commands/chat-commands-shared.ts +114 -0
  225. package/src/commands/chat-commands-write.ts +891 -0
  226. package/src/commands/chat-commands.ts +19 -1841
  227. package/src/commands/cli-manager.ts +544 -26
  228. package/src/commands/handler.ts +841 -2
  229. package/src/commands/high-family/index.ts +28 -0
  230. package/src/commands/high-family/mesh-coordinator-launch.ts +678 -0
  231. package/src/commands/high-family/mesh-events.ts +80 -0
  232. package/src/commands/high-family/mesh-status.ts +710 -0
  233. package/src/commands/high-family/types.ts +76 -0
  234. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  235. package/src/commands/low-family/daemon-lifecycle.ts +107 -0
  236. package/src/commands/low-family/diagnostics.ts +57 -0
  237. package/src/commands/low-family/index.ts +37 -0
  238. package/src/commands/low-family/mesh-ledger.ts +62 -0
  239. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  240. package/src/commands/low-family/notification.ts +116 -0
  241. package/src/commands/low-family/refine-config.ts +106 -0
  242. package/src/commands/low-family/session-host.ts +274 -0
  243. package/src/commands/low-family/spec-providerdev.ts +217 -0
  244. package/src/commands/low-family/status-meta.ts +112 -0
  245. package/src/commands/low-family/types.ts +39 -0
  246. package/src/commands/med-family/cli-agent.ts +238 -0
  247. package/src/commands/med-family/fast-forward.ts +230 -0
  248. package/src/commands/med-family/ide.ts +163 -0
  249. package/src/commands/med-family/index.ts +37 -0
  250. package/src/commands/med-family/mesh-crud.ts +1066 -0
  251. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  252. package/src/commands/med-family/mesh-queue.ts +167 -0
  253. package/src/commands/med-family/mesh-restart.ts +92 -0
  254. package/src/commands/med-family/types.ts +143 -0
  255. package/src/commands/mesh-coordinator.ts +334 -124
  256. package/src/commands/router.ts +2711 -3254
  257. package/src/commands/stream-commands.ts +8 -0
  258. package/src/commands/upgrade-helper.ts +310 -45
  259. package/src/config/chat-history.ts +483 -24
  260. package/src/config/config.ts +12 -0
  261. package/src/config/mesh-config.ts +495 -22
  262. package/src/config/mesh-json-config.ts +376 -0
  263. package/src/config/recent-activity.ts +8 -2
  264. package/src/config/repo-settings.ts +111 -0
  265. package/src/daemon/dev-auto-implement.ts +3 -2
  266. package/src/daemon/dev-cli-debug.ts +10 -1
  267. package/src/daemon/dev-server.ts +0 -541
  268. package/src/detection/cli-detector.ts +28 -9
  269. package/src/detection/ide-detector.ts +55 -16
  270. package/src/detection/win32-ide-version.ts +106 -0
  271. package/src/git/change-impact-config.ts +354 -0
  272. package/src/git/git-commands.ts +59 -15
  273. package/src/git/git-diff.ts +81 -11
  274. package/src/git/git-executor.ts +12 -0
  275. package/src/git/git-status.ts +767 -48
  276. package/src/git/git-types.ts +14 -62
  277. package/src/git/git-worktree.ts +261 -4
  278. package/src/git/index.ts +17 -0
  279. package/src/index.ts +194 -12
  280. package/src/installer.d.ts +1 -1
  281. package/src/installer.ts +8 -6
  282. package/src/ipc/local-ipc-server.ts +278 -0
  283. package/src/launch.d.ts +1 -1
  284. package/src/launch.ts +37 -28
  285. package/src/logging/async-batch-writer.ts +55 -0
  286. package/src/logging/command-log.ts +7 -5
  287. package/src/logging/log-redactor.ts +100 -0
  288. package/src/logging/log-tail-reader.ts +341 -0
  289. package/src/logging/logger.ts +14 -7
  290. package/src/mesh/contracts.ts +338 -0
  291. package/src/mesh/coordinator-prompt.ts +381 -33
  292. package/src/mesh/coordinator-registry.ts +121 -0
  293. package/src/mesh/mesh-active-work.ts +645 -0
  294. package/src/mesh/mesh-clone-grace.ts +68 -0
  295. package/src/mesh/mesh-coordinator-config.ts +97 -0
  296. package/src/mesh/mesh-delivery-policy.ts +315 -0
  297. package/src/mesh/mesh-event-classify.ts +51 -0
  298. package/src/mesh/mesh-event-forwarding.ts +1888 -0
  299. package/src/mesh/mesh-event-trace.ts +67 -0
  300. package/src/mesh/mesh-events-coordinator.ts +32 -0
  301. package/src/mesh/mesh-events-pending.ts +656 -0
  302. package/src/mesh/mesh-events-stale.ts +389 -0
  303. package/src/mesh/mesh-events-utils.ts +443 -0
  304. package/src/mesh/mesh-events.ts +33 -1035
  305. package/src/mesh/mesh-fast-forward.ts +843 -0
  306. package/src/mesh/mesh-host-ownership.ts +73 -0
  307. package/src/mesh/mesh-init.ts +260 -0
  308. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  309. package/src/mesh/mesh-ledger.ts +656 -102
  310. package/src/mesh/mesh-magi-status.ts +223 -0
  311. package/src/mesh/mesh-missions.ts +449 -0
  312. package/src/mesh/mesh-node-identity.ts +1887 -0
  313. package/src/mesh/mesh-queue-assignment.ts +1918 -0
  314. package/src/mesh/mesh-reconcile-loop.ts +1780 -0
  315. package/src/mesh/mesh-refine-batch.ts +205 -0
  316. package/src/mesh/mesh-refine-gates.ts +1673 -0
  317. package/src/mesh/mesh-refine-status.ts +231 -0
  318. package/src/mesh/mesh-review-inbox.ts +307 -0
  319. package/src/mesh/mesh-routing.ts +291 -0
  320. package/src/mesh/mesh-runtime-store.ts +1853 -0
  321. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  322. package/src/mesh/mesh-task-inflight.ts +70 -0
  323. package/src/mesh/mesh-task-stats.ts +161 -0
  324. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  325. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  326. package/src/mesh/mesh-work-queue.ts +1243 -141
  327. package/src/mesh/preview-freshness.ts +118 -0
  328. package/src/mesh/refine-config.ts +423 -0
  329. package/src/mesh/worktree-bootstrap-config.ts +450 -0
  330. package/src/providers/acp-provider-instance.ts +43 -10
  331. package/src/providers/approval-utils.d.ts +5 -0
  332. package/src/providers/approval-utils.ts +57 -5
  333. package/src/providers/chat-message-normalization.ts +92 -4
  334. package/src/providers/cli-provider-instance.ts +1933 -104
  335. package/src/providers/contracts.d.ts +55 -0
  336. package/src/providers/contracts.ts +150 -6
  337. package/src/providers/extension-provider-instance.ts +12 -7
  338. package/src/providers/external-sources.ts +218 -0
  339. package/src/providers/ide-provider-instance.ts +35 -12
  340. package/src/providers/manual-attendance.ts +85 -0
  341. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  342. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  343. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  344. package/src/providers/native-history/constants.ts +19 -0
  345. package/src/providers/native-history/dispatcher.ts +339 -0
  346. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  347. package/src/providers/native-history/index.ts +30 -0
  348. package/src/providers/provider-instance-manager.ts +71 -0
  349. package/src/providers/provider-instance.ts +19 -1
  350. package/src/providers/provider-loader.ts +668 -50
  351. package/src/providers/provider-schema.ts +87 -14
  352. package/src/providers/provider-trust.ts +114 -0
  353. package/src/providers/read-chat-contract.ts +76 -16
  354. package/src/providers/sdk/README.md +49 -0
  355. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  356. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  357. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  358. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  359. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  360. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  361. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  362. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  363. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  364. package/src/providers/sdk/v1/index.ts +152 -0
  365. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  366. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  367. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  368. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
  369. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  370. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  371. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  372. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  373. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  374. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  375. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  376. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  377. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  378. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  379. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  380. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  381. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  382. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  383. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  384. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  385. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  386. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  387. package/src/providers/sdk/v1/validators/index.ts +19 -0
  388. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  389. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  390. package/src/providers/spec/adapter.ts +235 -0
  391. package/src/providers/spec/cli-adapter.ts +1056 -0
  392. package/src/providers/spec/evaluator.ts +407 -0
  393. package/src/providers/spec/fsm-driver.ts +1410 -0
  394. package/src/providers/spec/fsm-evaluator.ts +272 -0
  395. package/src/providers/spec/fsm-loader.ts +120 -0
  396. package/src/providers/spec/fsm-types.ts +273 -0
  397. package/src/providers/spec/native-history-executor.ts +1128 -0
  398. package/src/providers/spec/pre-launch-trust.ts +104 -0
  399. package/src/providers/spec/route.ts +51 -0
  400. package/src/providers/spec/types.ts +262 -0
  401. package/src/providers/status-monitor.d.ts +7 -7
  402. package/src/providers/status-monitor.ts +37 -22
  403. package/src/providers/transcript-v2.ts +567 -0
  404. package/src/providers/types/interactive-prompt.ts +536 -0
  405. package/src/providers/version-archive.ts +64 -24
  406. package/src/providers/working-dir.ts +23 -0
  407. package/src/repo-mesh-types.ts +740 -14
  408. package/src/runtime-defaults.ts +39 -0
  409. package/src/sessions/registry.ts +6 -0
  410. package/src/shared-types-extra.ts +2 -4
  411. package/src/shared-types.d.ts +8 -0
  412. package/src/shared-types.ts +64 -1
  413. package/src/status/builders.ts +26 -6
  414. package/src/status/normalize.ts +2 -0
  415. package/src/status/reporter.ts +19 -1
  416. package/src/status/snapshot.ts +95 -26
  417. package/src/system/hash.ts +23 -0
  418. package/src/system/host-memory.ts +29 -12
  419. package/src/system/load-better-sqlite3.ts +68 -0
  420. package/src/types.ts +5 -0
  421. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  422. package/dist/mesh/mesh-sync.d.ts +0 -53
  423. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  424. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  425. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,272 @@
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 cursor_above region. Key = cursor_above
32
+ * value (0 / undefined → whole-screen, keyed as -1). Missing key means
33
+ * "never observed changing" → treated as stable since stateEnteredAt. */
34
+ regionLastChangedAt: Map<number, number>;
35
+ }
36
+
37
+ /** Per-condition evaluation detail — the debugging payload. */
38
+ export interface CondResult {
39
+ kind: 'regex' | 'changed' | 'elapsed' | 'stable' | 'all' | 'any' | 'not';
40
+ result: boolean;
41
+ detail: string;
42
+ /** Remaining ms until a time-based condition would flip to true. 0 if
43
+ * already true or not applicable. Lets the UI show a countdown. */
44
+ remainingMs?: number;
45
+ /** Debug-only: the actual substring a TRUE regex condition matched, so the
46
+ * snapshot shows WHAT text the rule fired on — not just which regex. Never
47
+ * read by the FSM; purely for the Spec Debug Snapshot. */
48
+ matchedText?: string;
49
+ children?: CondResult[];
50
+ }
51
+
52
+ /** One evaluated transition with its full reasoning. */
53
+ export interface TransitionEval {
54
+ to: string;
55
+ label: string;
56
+ /** Did the `from` clause include the current state? (Always true for the
57
+ * transitions we return — kept for completeness.) */
58
+ eligible: boolean;
59
+ /** min_hold_ms guard satisfied? */
60
+ holdSatisfied: boolean;
61
+ holdRemainingMs: number;
62
+ /** Guard condition result (true if no `when`). */
63
+ condResult: boolean;
64
+ cond?: CondResult;
65
+ /** Overall: would this transition fire? */
66
+ fires: boolean;
67
+ priority: number;
68
+ }
69
+
70
+ export interface FsmEvaluation {
71
+ /** Sections resolved from the screen (shared with v3 shape). */
72
+ sections: ResolvedSection[];
73
+ /** Every outgoing transition from the current state, priority-ordered,
74
+ * each annotated with why it fired or didn't. */
75
+ transitions: TransitionEval[];
76
+ /** The transition that fires (first in priority order with fires===true),
77
+ * or null to stay in the current state. */
78
+ fired: TransitionEval | null;
79
+ /** v3-compatible trace lines for the legacy inspector. */
80
+ trace: TraceEntry[];
81
+ }
82
+
83
+ const WHOLE_SCREEN = -1;
84
+
85
+ function regionKey(cursorAbove: number | undefined): number {
86
+ return cursorAbove && cursorAbove > 0 ? cursorAbove : WHOLE_SCREEN;
87
+ }
88
+
89
+ function isRegex(c: FsmCondition): c is import('./types.js').RegexCondition {
90
+ return 'matches' in c;
91
+ }
92
+ function isChanged(c: FsmCondition): c is import('./types.js').ChangedCondition {
93
+ return 'cursor_above' in c && 'changed' in c;
94
+ }
95
+ function isElapsed(c: FsmCondition): c is import('./fsm-types.js').ElapsedCondition {
96
+ return 'elapsed_ms' in c;
97
+ }
98
+ function isStable(c: FsmCondition): c is import('./fsm-types.js').StableCondition {
99
+ return 'stable_ms' in c;
100
+ }
101
+ function isAll(c: FsmCondition): c is import('./fsm-types.js').FsmAllCondition {
102
+ return 'all' in c;
103
+ }
104
+ function isAny(c: FsmCondition): c is import('./fsm-types.js').FsmAnyCondition {
105
+ return 'any' in c;
106
+ }
107
+ function isNot(c: FsmCondition): c is import('./fsm-types.js').FsmNotCondition {
108
+ return 'not' in c;
109
+ }
110
+
111
+ /**
112
+ * Evaluate a single FSM condition into a {result, detail, remainingMs, children}.
113
+ * Recurses through all/any/not; defers regex/changed to the shared evaluator;
114
+ * handles elapsed_ms/stable_ms against the clock.
115
+ */
116
+ function evalCond(
117
+ cond: FsmCondition,
118
+ sections: ResolvedSection[],
119
+ fullScreen: string,
120
+ cursor: { row: number; col: number } | undefined,
121
+ prevLines: string[] | undefined,
122
+ clock: FsmClock,
123
+ legacyTrace: TraceEntry[],
124
+ stateId: string,
125
+ ): CondResult {
126
+ if (isAll(cond)) {
127
+ const children = cond.all.map(c =>
128
+ evalCond(c, sections, fullScreen, cursor, prevLines, clock, legacyTrace, stateId));
129
+ const result = children.every(c => c.result);
130
+ const remainingMs = result ? 0 : Math.max(0, ...children.filter(c => !c.result).map(c => c.remainingMs ?? 0));
131
+ return { kind: 'all', result, detail: `all(${children.length})`, remainingMs, children };
132
+ }
133
+ if (isAny(cond)) {
134
+ const children = cond.any.map(c =>
135
+ evalCond(c, sections, fullScreen, cursor, prevLines, clock, legacyTrace, stateId));
136
+ const result = children.some(c => c.result);
137
+ // remaining = the soonest child that could flip true
138
+ const pending = children.filter(c => !c.result).map(c => c.remainingMs ?? Infinity);
139
+ const remainingMs = result ? 0 : (pending.length ? Math.min(...pending) : 0);
140
+ return { kind: 'any', result, detail: `any(${children.length})`, remainingMs: Number.isFinite(remainingMs) ? remainingMs : 0, children };
141
+ }
142
+ if (isNot(cond)) {
143
+ const child = evalCond(cond.not, sections, fullScreen, cursor, prevLines, clock, legacyTrace, stateId);
144
+ return { kind: 'not', result: !child.result, detail: `not`, remainingMs: 0, children: [child] };
145
+ }
146
+ if (isElapsed(cond)) {
147
+ const age = clock.now - clock.stateEnteredAt;
148
+ const result = age >= cond.elapsed_ms;
149
+ const remainingMs = result ? 0 : cond.elapsed_ms - age;
150
+ return { kind: 'elapsed', result, detail: `elapsed ${age}ms / ${cond.elapsed_ms}ms`, remainingMs };
151
+ }
152
+ if (isStable(cond)) {
153
+ const key = regionKey(cond.cursor_above);
154
+ // If we never saw the region change, treat it as stable since the
155
+ // state was entered (conservative — avoids a premature "stable" on
156
+ // the very first frame).
157
+ const lastChanged = clock.regionLastChangedAt.get(key) ?? clock.stateEnteredAt;
158
+ const stableFor = clock.now - lastChanged;
159
+ const result = stableFor >= cond.stable_ms;
160
+ const remainingMs = result ? 0 : cond.stable_ms - stableFor;
161
+ const where = key === WHOLE_SCREEN ? 'screen' : `cursor_above=${cond.cursor_above}`;
162
+ return { kind: 'stable', result, detail: `stable ${where} ${stableFor}ms / ${cond.stable_ms}ms`, remainingMs };
163
+ }
164
+ // regex / changed → shared evaluator (operates on v3 Condition shape)
165
+ if (isRegex(cond) || isChanged(cond)) {
166
+ const result = evaluateCondition(cond as Condition, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
167
+ const kind = isRegex(cond) ? 'regex' : 'changed';
168
+ const detail = isRegex(cond)
169
+ ? `${(cond as any).section ?? '*'}~/${(cond as any).matches}/`
170
+ : `cursor_above=${(cond as any).cursor_above} changed=${(cond as any).changed}`;
171
+ // Debug-only: when a regex condition is TRUE, also capture the substring
172
+ // it matched so the snapshot can show the exact text the rule fired on.
173
+ // This re-runs the regex (read-only) and CANNOT change `result` above —
174
+ // the FSM decision is still entirely owned by evaluateCondition().
175
+ let matchedText: string | undefined;
176
+ if (result && isRegex(cond)) {
177
+ try {
178
+ const hay = sectionText(sections, (cond as any).section, fullScreen);
179
+ const re = new RegExp((cond as any).matches, (cond as any).flags ?? 'i');
180
+ const m = re.exec(hay);
181
+ if (m && m[0]) matchedText = m[0].replace(/\s+/g, ' ').trim().slice(0, 160);
182
+ } catch { /* capture is best-effort; never affects result */ }
183
+ }
184
+ return matchedText ? { kind, result, detail, matchedText } : { kind, result, detail };
185
+ }
186
+ return { kind: 'all', result: false, detail: 'unknown condition' };
187
+ }
188
+
189
+ function fromLabel(t: FsmTransition): string {
190
+ const from = Array.isArray(t.from) ? t.from.join('|') : t.from;
191
+ return t.label ?? `${from}→${t.to}`;
192
+ }
193
+
194
+ /**
195
+ * Evaluate the FSM: given the current state id and screen, return every
196
+ * outgoing transition annotated with why it fires/doesn't, plus the one that
197
+ * fires (if any).
198
+ */
199
+ export function evaluateFsm(
200
+ spec: CliSpecV4,
201
+ currentStateId: string,
202
+ screenText: string,
203
+ cursor: { row: number; col: number } | undefined,
204
+ prevLines: string[] | undefined,
205
+ clock: FsmClock,
206
+ ): FsmEvaluation {
207
+ const legacyTrace: TraceEntry[] = [];
208
+ const lines = screenText.split('\n').map(l => l.endsWith('\r') ? l.slice(0, -1) : l);
209
+ const cleanScreen = lines.join('\n');
210
+ const sections = resolveSections(spec.sections ?? {}, lines);
211
+
212
+ const outgoing = outgoingTransitions(spec, currentStateId);
213
+ const transitions: TransitionEval[] = [];
214
+ let fired: TransitionEval | null = null;
215
+
216
+ for (const t of outgoing) {
217
+ const holdMs = t.min_hold_ms ?? 0;
218
+ const heldFor = clock.now - clock.stateEnteredAt;
219
+ const holdSatisfied = heldFor >= holdMs;
220
+ const holdRemainingMs = holdSatisfied ? 0 : holdMs - heldFor;
221
+
222
+ let cond: CondResult | undefined;
223
+ let condResult = true;
224
+ if (t.when) {
225
+ cond = evalCond(t.when, sections, cleanScreen, cursor, prevLines, clock, legacyTrace, `${currentStateId}→${t.to}`);
226
+ condResult = cond.result;
227
+ }
228
+
229
+ const fires = holdSatisfied && condResult;
230
+ const te: TransitionEval = {
231
+ to: t.to,
232
+ label: fromLabel(t),
233
+ eligible: true,
234
+ holdSatisfied,
235
+ holdRemainingMs,
236
+ condResult,
237
+ cond,
238
+ fires,
239
+ priority: t.priority ?? 0,
240
+ };
241
+ transitions.push(te);
242
+ if (fires && !fired) fired = te;
243
+ }
244
+
245
+ // Validate destination exists (defensive — loader should catch this).
246
+ if (fired && !stateById(spec, fired.to)) {
247
+ legacyTrace.push({ kind: 'state_skip', text: `transition target ${fired.to} not found` });
248
+ fired = null;
249
+ }
250
+
251
+ return { sections, transitions, fired, trace: legacyTrace };
252
+ }
253
+
254
+ /**
255
+ * Evaluate a single condition against a screen + section map — for the spec
256
+ * editor's live preview ("does this regex match the current screen right
257
+ * now?"). Time leaves (elapsed_ms/stable_ms) are evaluated against a synthetic
258
+ * clock where the state was just entered, so they report their countdown
259
+ * rather than firing; the preview is about screen-content match, not timing.
260
+ */
261
+ export function evaluateConditionPreview(
262
+ cond: FsmCondition,
263
+ sections: Record<string, SectionDef> | undefined,
264
+ screenText: string,
265
+ cursor?: { row: number; col: number },
266
+ ): CondResult {
267
+ const lines = screenText.split('\n').map(l => l.endsWith('\r') ? l.slice(0, -1) : l);
268
+ const cleanScreen = lines.join('\n');
269
+ const resolved = resolveSections(sections ?? {}, lines);
270
+ const clock: FsmClock = { now: 0, stateEnteredAt: 0, regionLastChangedAt: new Map() };
271
+ return evalCond(cond, resolved, cleanScreen, cursor, undefined, clock, [], 'preview');
272
+ }
@@ -0,0 +1,120 @@
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) { if (typeof w.stable_ms !== 'number') errs.push(`${path}.stable_ms must be a number`); return errs; }
118
+ errs.push(`${path} is not a recognized condition`);
119
+ return errs;
120
+ }
@@ -0,0 +1,273 @@
1
+ /**
2
+ * adhdev:cli/spec@4 — declarative FSM spec.
3
+ *
4
+ * A v4 spec describes a finite state machine the same way a Unity animator
5
+ * layer does: states are nodes, transitions are directed edges with a guard
6
+ * condition. The engine (fsm-driver.ts) holds ZERO CLI-specific knowledge —
7
+ * every concept that used to live in the driver as a hard-coded debounce
8
+ * (startup grace, busy hold, completion marker, idle hold) is now expressed
9
+ * declaratively as either a state, a transition condition, or a transition
10
+ * guard. To support a new CLI you write a spec; you never touch the engine.
11
+ *
12
+ * Reuses v3's section system (sections{}) and condition system (regex /
13
+ * changed / all / any) verbatim — see types.ts. v4 only adds the FSM layer
14
+ * (states[] + transitions[]) on top and two new leaf conditions that are
15
+ * inherently time-based:
16
+ *
17
+ * - elapsed_ms : true once N ms have passed since the CURRENT state was
18
+ * entered. Replaces startup_grace_ms (a `starting` state with
19
+ * one `elapsed_ms` transition to idle).
20
+ * - stable_ms : true once the cursor_above region has been UNCHANGED for
21
+ * N ms. Replaces screen_active_hold_ms / the old changed:false
22
+ * + stable_ms combo. Pure region-stability gate.
23
+ *
24
+ * Both are evaluated by the driver (which owns the clock); the shared
25
+ * condition evaluator handles the screen-content leaves (regex / changed).
26
+ */
27
+ 'use strict';
28
+
29
+ import type {
30
+ RegexCondition, ChangedCondition,
31
+ Control, NotificationRule, DelegateTrigger,
32
+ NativeHistoryConfig, SectionDef, ExtractTitle, ExtractButtons,
33
+ } from './types.js';
34
+
35
+ // ─────────────────────────────────────────────────────────────────────────────
36
+ // Conditions (v4)
37
+ //
38
+ // Superset of v3 conditions. Adds the two time-based leaves. The shared
39
+ // evaluator handles regex/changed; the driver handles elapsed_ms/stable_ms
40
+ // because they need the wall clock and per-region change timestamps.
41
+ // ─────────────────────────────────────────────────────────────────────────────
42
+
43
+ /** True once `ms` have elapsed since the current state was entered. */
44
+ export interface ElapsedCondition {
45
+ elapsed_ms: number;
46
+ }
47
+
48
+ /** True once the region `cursor_above` lines above the cursor has been
49
+ * unchanged for `ms`. A stability gate — the inverse of a busy signal. */
50
+ export interface StableCondition {
51
+ stable_ms: number;
52
+ /** Lines above the cursor that must be stable. Default: whole screen. */
53
+ cursor_above?: number;
54
+ }
55
+
56
+ export interface FsmAllCondition {
57
+ all: FsmCondition[];
58
+ }
59
+
60
+ export interface FsmAnyCondition {
61
+ any: FsmCondition[];
62
+ }
63
+
64
+ /** Negation — true when the inner condition is false. Lets a transition say
65
+ * "go busy unless the completion marker is present", etc. */
66
+ export interface FsmNotCondition {
67
+ not: FsmCondition;
68
+ }
69
+
70
+ export type FsmCondition =
71
+ | RegexCondition
72
+ | ChangedCondition
73
+ | ElapsedCondition
74
+ | StableCondition
75
+ | FsmAllCondition
76
+ | FsmAnyCondition
77
+ | FsmNotCondition;
78
+
79
+ // ─────────────────────────────────────────────────────────────────────────────
80
+ // States & transitions (v4)
81
+ // ─────────────────────────────────────────────────────────────────────────────
82
+
83
+ export interface FsmState {
84
+ id: string;
85
+ label: string;
86
+ /** Exactly one state must be `initial: true` — the state at spawn. */
87
+ initial?: boolean;
88
+ /** Modal states (approval/picker) expose modal buttons in the UI and are
89
+ * treated as "interesting" — the dashboard surfaces them distinctly. */
90
+ modal?: boolean;
91
+ /**
92
+ * For a modal state, what KIND of modal it is — the semantic distinction the
93
+ * status field (always 'approval' for any modal, so the dashboard surfaces it)
94
+ * deliberately loses. The auto-approve worker uses this to decide whether it
95
+ * may answer the modal on the user's behalf:
96
+ *
97
+ * - 'approval' — a tool/command/trust consent prompt ("Allow Bash?",
98
+ * "Trust this folder?"). Auto-approve MAY fire (a background mesh worker
99
+ * should not stall on these).
100
+ * - 'picker' — a selection menu the user opened (/model, /mode, …). There
101
+ * is no "correct" answer to auto-pick; blindly selecting the first option
102
+ * silently changes the model/mode. Auto-approve must NOT fire — the user
103
+ * chooses.
104
+ * - 'confirm' — a non-consent yes/no the user must decide. Left to the user.
105
+ *
106
+ * Defaults to 'approval' for a modal state that omits it (preserves the
107
+ * pre-existing "auto-approve any modal" behaviour for un-migrated specs;
108
+ * picker/confirm states declare their kind explicitly). Non-modal states
109
+ * have no modal_kind.
110
+ */
111
+ modal_kind?: 'approval' | 'picker' | 'confirm';
112
+ /** Status this state maps to for the dashboard/cli-adapter status field.
113
+ * One of: idle | generating | approval. Defaults: modal→approval,
114
+ * initial→idle, id==='busy'→generating, else idle. Explicit wins. */
115
+ status?: 'idle' | 'generating' | 'approval';
116
+ /** Optional extraction run whenever this state is the committed state —
117
+ * used by modal states to surface a title + buttons. */
118
+ extract?: {
119
+ title?: ExtractTitle;
120
+ buttons?: ExtractButtons;
121
+ };
122
+ }
123
+
124
+ export interface FsmTransition {
125
+ /** Source state id, or list of source ids, or "*" for any state. */
126
+ from: string | string[];
127
+ /** Destination state id. */
128
+ to: string;
129
+ /** Guard condition. Omitted → always eligible (only gated by `from` +
130
+ * min_hold_ms). Evaluated against the current screen + clock. */
131
+ when?: FsmCondition;
132
+ /** Minimum time the machine must have been in `from` before this edge can
133
+ * fire. Replaces busy_hold_ms / idle_hold_ms (per-edge, not global). */
134
+ min_hold_ms?: number;
135
+ /** Higher priority transitions are evaluated first. Default 0. Ties broken
136
+ * by declaration order. */
137
+ priority?: number;
138
+ /** Human label for the debugger. */
139
+ label?: string;
140
+ }
141
+
142
+ /**
143
+ * Declarative "trust this folder before spawn" config. Some agent CLIs gate the
144
+ * first run in a new folder behind an interactive trust prompt and persist the
145
+ * answer as a string array in a JSON settings file. Declaring this lets the
146
+ * engine add the workspace path to that array before spawn so the prompt never
147
+ * appears — the robust alternative to detecting and auto-clicking the modal.
148
+ * CLIs without such a gate omit this field and the engine does nothing.
149
+ */
150
+ export interface PreLaunchTrust {
151
+ /** Path to the CLI's JSON settings file. A leading `~` expands to $HOME. */
152
+ settings_path: string;
153
+ /** Key of the string-array of trusted folder paths within that file. */
154
+ key: string;
155
+ }
156
+
157
+ // ─────────────────────────────────────────────────────────────────────────────
158
+ // CliSpecV4 — the v4 runtime spec
159
+ // ─────────────────────────────────────────────────────────────────────────────
160
+
161
+ export interface CliSpecV4 {
162
+ $schema: 'adhdev:cli/spec@4';
163
+ id: string;
164
+ name: string;
165
+ binary: string;
166
+ spawn_args?: string[];
167
+ env?: Record<string, string>;
168
+ cli_version_range?: string;
169
+ /**
170
+ * Optional raw byte sequences written to the PTY once, shortly after spawn,
171
+ * to prime a TUI that gates its input handling on a terminal event the
172
+ * daemon would otherwise never emit. The canonical case is a focus-event
173
+ * TUI (Ink `useStdin`/`useFocus`, e.g. antigravity's `agy`) that enables
174
+ * focus reporting (`CSI ?1004h`) and treats its input box as unfocused —
175
+ * silently dropping the first programmatic write — until it receives a
176
+ * focus-in event (`ESC [ I`). Declaring `[""]` here wakes the input
177
+ * stream on spawn so the first delegated message lands without a manual
178
+ * keystroke. CLIs that do not focus-gate input simply omit this field; the
179
+ * engine writes nothing extra for them, so it stays CLI-agnostic.
180
+ */
181
+ send_on_spawn?: string[];
182
+ /** Delay (ms) after spawn before writing `send_on_spawn`. Default 250. */
183
+ send_on_spawn_delay_ms?: number;
184
+ /**
185
+ * Opt-in stall recovery for focus-gated TUIs. The same CLIs that need
186
+ * `send_on_spawn` (focus-event TUIs like antigravity's `agy`) also stop
187
+ * rendering / flushing output the moment they believe they have lost focus
188
+ * MID-TURN — the screen freezes and only repaints once the user presses a
189
+ * key, which the daemon never does on its own. When this field is set and
190
+ * the machine is in a `generating`-status state whose screen has not changed
191
+ * for `refocus_when_stalled_ms`, the engine re-injects the `send_on_spawn`
192
+ * prime (the focus-in event) once to wake the render loop, then waits for the
193
+ * screen to change or for the stall window to lapse again before re-priming
194
+ * (a cooldown that prevents a tight re-prime loop). Requires `send_on_spawn`
195
+ * to carry the wake sequence; with no `send_on_spawn` there is nothing to
196
+ * re-inject and the engine does nothing. Omitted by every non-focus-gated
197
+ * CLI spec, so the engine stays CLI-agnostic.
198
+ */
199
+ refocus_when_stalled_ms?: number;
200
+ /**
201
+ * Optional pre-spawn folder-trust step. When present, the engine adds the
202
+ * launch workspace path to the declared trusted-folders array before
203
+ * spawning, so a CLI that gates first run on a "trust this folder?" prompt
204
+ * (e.g. antigravity's `agy`) starts trusted and never blocks. Omitted for
205
+ * CLIs without such a gate. See pre-launch-trust.ts.
206
+ */
207
+ pre_launch_trust?: PreLaunchTrust;
208
+ send_message: {
209
+ submit_key: string;
210
+ delay_ms_before_submit?: number;
211
+ delay_ms_per_char?: number;
212
+ };
213
+ sections: Record<string, SectionDef>;
214
+ states: FsmState[];
215
+ transitions: FsmTransition[];
216
+ control_bar?: Control[];
217
+ notifications?: NotificationRule[];
218
+ delegate?: DelegateTrigger[];
219
+ native_history?: NativeHistoryConfig;
220
+ requiresFinalAssistantBeforeIdle?: boolean;
221
+ }
222
+
223
+ export function isV4Spec(raw: unknown): raw is CliSpecV4 {
224
+ return !!raw && typeof raw === 'object'
225
+ && (raw as { $schema?: string }).$schema === 'adhdev:cli/spec@4';
226
+ }
227
+
228
+ export function initialState(spec: CliSpecV4): FsmState {
229
+ return spec.states.find(s => s.initial) ?? spec.states[0];
230
+ }
231
+
232
+ export function stateById(spec: CliSpecV4, id: string): FsmState | undefined {
233
+ return spec.states.find(s => s.id === id);
234
+ }
235
+
236
+ /** Outgoing transitions from `stateId`, highest priority first, declaration
237
+ * order as tiebreak. Includes wildcard ("*") and list-membership sources. */
238
+ export function outgoingTransitions(spec: CliSpecV4, stateId: string): FsmTransition[] {
239
+ const matches = spec.transitions.filter(t => {
240
+ if (t.from === '*') return true;
241
+ if (Array.isArray(t.from)) return t.from.includes(stateId);
242
+ return t.from === stateId;
243
+ });
244
+ // Stable sort by priority desc; Array.prototype.sort is stable in V8 so
245
+ // equal-priority edges keep declaration order.
246
+ return matches
247
+ .map((t, i) => ({ t, i }))
248
+ .sort((a, b) => (b.t.priority ?? 0) - (a.t.priority ?? 0) || a.i - b.i)
249
+ .map(x => x.t);
250
+ }
251
+
252
+ /** Map a state to the dashboard status string, applying the documented
253
+ * defaults when `status` is not explicit. */
254
+ export function statusForState(state: FsmState): 'idle' | 'generating' | 'approval' {
255
+ if (state.status) return state.status;
256
+ if (state.modal) return 'approval';
257
+ if (state.id === 'busy' || state.id === 'generating') return 'generating';
258
+ return 'idle';
259
+ }
260
+
261
+ /**
262
+ * The modal kind for a state, or null when the state is not modal. A modal state
263
+ * that omits `modal_kind` defaults to 'approval' so the established
264
+ * auto-approve-any-modal behaviour is preserved for specs that have not yet
265
+ * declared a kind; picker/confirm states must opt out by declaring their kind.
266
+ * This is the value the cli-adapter carries on `activeModal.kind` and the
267
+ * auto-approve gate reads — see cli-provider-instance.maybeAutoApproveStatus.
268
+ */
269
+ export function modalKindForState(state: FsmState): 'approval' | 'picker' | 'confirm' | null {
270
+ if (state.modal_kind) return state.modal_kind;
271
+ if (state.modal) return 'approval';
272
+ return null;
273
+ }