@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,110 @@
1
+ /**
2
+ * Manifest validators — runtime JSON Schema check for v1 provider manifests.
3
+ *
4
+ * The schemas live under `schemas/{category}/provider.schema.json` and are
5
+ * the authoritative contract for what a v1 manifest may contain. Daemon
6
+ * code that loads a manifest at install or boot time runs it through
7
+ * `validateCliProviderManifest()` first; failures are reported back to
8
+ * the caller with structured paths so manifest authors can locate the
9
+ * offending field without guessing.
10
+ *
11
+ * Validation lives in the SDK layer (not in provider-loader) so dashboards,
12
+ * registry workers, and the provider publish flow can all reuse the
13
+ * same code path and produce identical error messages.
14
+ */
15
+
16
+ import Ajv2020, { type ErrorObject, type ValidateFunction } from 'ajv/dist/2020.js';
17
+ import addFormats from 'ajv-formats';
18
+ import cliProviderSchema from '../schemas/cli/provider.schema.json';
19
+
20
+ export interface ManifestValidationIssue {
21
+ /** JSON Pointer-style path into the manifest. Empty string for the root. */
22
+ path: string;
23
+ /** Schema-keyword that failed. */
24
+ keyword: string;
25
+ /** Human-readable explanation. */
26
+ message: string;
27
+ /** Allowed values when the failure is an `enum` / `const` / `additionalProperties`. */
28
+ allowed?: unknown;
29
+ }
30
+
31
+ export interface ManifestValidationResult {
32
+ ok: boolean;
33
+ issues: ManifestValidationIssue[];
34
+ }
35
+
36
+ let _ajv: Ajv2020 | null = null;
37
+ let _cliValidator: ValidateFunction | null = null;
38
+
39
+ function getAjv(): Ajv2020 {
40
+ if (_ajv) return _ajv;
41
+ // strict=false because the schema authors freely use schema-level
42
+ // `description`/`examples` fields that ajv would otherwise warn about.
43
+ // allErrors=true so a single validation run reports every problem at
44
+ // once instead of bailing on the first — that's what makes the
45
+ // structured-error output usable for manifest authors.
46
+ _ajv = new Ajv2020({
47
+ strict: false,
48
+ allErrors: true,
49
+ allowUnionTypes: true,
50
+ });
51
+ addFormats(_ajv);
52
+ return _ajv;
53
+ }
54
+
55
+ function getCliValidator(): ValidateFunction {
56
+ if (_cliValidator) return _cliValidator;
57
+ _cliValidator = getAjv().compile(cliProviderSchema as unknown as object);
58
+ return _cliValidator;
59
+ }
60
+
61
+ function formatIssue(err: ErrorObject): ManifestValidationIssue {
62
+ const path = err.instancePath || '';
63
+ const params = err.params as Record<string, unknown>;
64
+ let message = err.message || 'validation failed';
65
+ let allowed: unknown;
66
+
67
+ if (err.keyword === 'additionalProperties') {
68
+ const extra = params.additionalProperty;
69
+ message = `unexpected property "${extra}"`;
70
+ } else if (err.keyword === 'required') {
71
+ message = `missing required property "${params.missingProperty}"`;
72
+ } else if (err.keyword === 'enum') {
73
+ allowed = params.allowedValues;
74
+ message = `must be one of ${JSON.stringify(allowed)}`;
75
+ } else if (err.keyword === 'const') {
76
+ allowed = params.allowedValue;
77
+ message = `must equal ${JSON.stringify(allowed)}`;
78
+ } else if (err.keyword === 'type') {
79
+ message = `must be ${params.type}`;
80
+ }
81
+
82
+ return { path, keyword: err.keyword, message, ...(allowed !== undefined ? { allowed } : {}) };
83
+ }
84
+
85
+ /**
86
+ * Validate a CLI provider.v1.json manifest. Returns `{ ok: true, issues: [] }`
87
+ * on success and `{ ok: false, issues: [...] }` on failure with each issue
88
+ * pointing at the offending field. Never throws — manifest parse errors
89
+ * should be caught by the caller before this is called.
90
+ */
91
+ export function validateCliProviderManifest(manifest: unknown): ManifestValidationResult {
92
+ const validator = getCliValidator();
93
+ const ok = validator(manifest) as boolean;
94
+ if (ok) return { ok: true, issues: [] };
95
+ const issues = (validator.errors || []).map(formatIssue);
96
+ return { ok: false, issues };
97
+ }
98
+
99
+ /**
100
+ * Render a list of validation issues as a single multi-line string,
101
+ * suitable for log lines or daemon command error fields.
102
+ */
103
+ export function formatManifestValidationIssues(issues: ManifestValidationIssue[]): string {
104
+ return issues
105
+ .map((issue) => {
106
+ const where = issue.path || '<root>';
107
+ return ` - ${where}: ${issue.message} (${issue.keyword})`;
108
+ })
109
+ .join('\n');
110
+ }
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Static taint analyzer for extended-tier override JS.
3
+ *
4
+ * Goal: classify the override JS shipped with an extended-tier provider into
5
+ * one of three risk tiers, so the dashboard + daemon trust prompt can
6
+ * surface accurate language to the operator instead of a single generic
7
+ * "this provider contains JS" warning.
8
+ *
9
+ * - clean : no flagged APIs at all. The override looks like pure string
10
+ * manipulation. Still extended-tier, but the warning copy is
11
+ * "this provider contains JS; nothing dangerous was detected".
12
+ * - elevated : touches process / dynamic codegen / dynamic require / eval
13
+ * / Function constructor / child_process. The warning copy is
14
+ * explicit ("this provider can run shell commands / dynamically
15
+ * load code").
16
+ * - hostile : combines elevated APIs with network egress, AND uses obvious
17
+ * obfuscation (base64-decoded strings fed into Function / eval).
18
+ * The publish endpoint should reject these.
19
+ *
20
+ * Implementation note: this is a *static* analyzer — string + light AST scan
21
+ * via Node's built-in parser. It is intentionally fail-loud: anything that
22
+ * looks suspicious is flagged. False positives are fine; this exists to gate
23
+ * the trust prompt, not to be a real sandbox. The real sandbox lives in
24
+ * Phase 5 (isolated-vm).
25
+ *
26
+ * Used by:
27
+ * - `adhdev provider validate` (CLI tier classification)
28
+ * - registry publish endpoint static-check
29
+ * - daemon at provider-load time, to size the warning
30
+ */
31
+
32
+ import { readFileSync, existsSync } from 'node:fs';
33
+ import { resolve, dirname, join } from 'node:path';
34
+
35
+ // ─── Findings ──────────────────────────────────────────────────────────
36
+
37
+ export type TaintLevel = 'clean' | 'elevated' | 'hostile';
38
+
39
+ export interface TaintFinding {
40
+ /** What was found, e.g. "child_process.exec". */
41
+ api: string;
42
+ /** Coarse category. */
43
+ category: TaintCategory;
44
+ /** File the finding came from. */
45
+ file: string;
46
+ /** Line number (1-indexed) of the first character of the matched token. */
47
+ line: number;
48
+ /** The surrounding source excerpt, trimmed. */
49
+ excerpt: string;
50
+ }
51
+
52
+ export type TaintCategory =
53
+ | 'process-control' // process.exit, process.kill
54
+ | 'shell-exec' // child_process.{exec,execSync,spawn,spawnSync,fork}
55
+ | 'fs-write' // fs.writeFile / writeFileSync outside override dir
56
+ | 'fs-read' // fs.readFile / readFileSync
57
+ | 'network' // http(s).request, fetch, net.connect, dgram
58
+ | 'dynamic-codegen' // eval, new Function(), Function('...')
59
+ | 'dynamic-require' // require(variable), import(variable)
60
+ | 'obfuscation' // Buffer.from(...,'base64').toString + (eval|Function)
61
+ | 'global-mutation'; // mutating Object.prototype, process.env
62
+
63
+ export interface TaintResult {
64
+ level: TaintLevel;
65
+ findings: TaintFinding[];
66
+ files: string[];
67
+ }
68
+
69
+ // ─── Patterns ──────────────────────────────────────────────────────────
70
+
71
+ interface PatternRule {
72
+ category: TaintCategory;
73
+ /** Display label. */
74
+ label: string;
75
+ /** Regex applied per-line. */
76
+ pattern: RegExp;
77
+ }
78
+
79
+ const PATTERNS: PatternRule[] = [
80
+ {
81
+ category: 'shell-exec',
82
+ label: 'child_process.exec',
83
+ pattern: /\bchild_process\b[\s\S]{0,40}?\b(exec|execSync|spawn|spawnSync|fork|execFile)\b/,
84
+ },
85
+ {
86
+ category: 'shell-exec',
87
+ label: 'require("child_process")',
88
+ pattern: /\brequire\s*\(\s*['"]child_process['"]\s*\)/,
89
+ },
90
+ {
91
+ category: 'shell-exec',
92
+ label: 'import child_process',
93
+ pattern: /\bfrom\s+['"](?:node:)?child_process['"]/,
94
+ },
95
+ {
96
+ category: 'process-control',
97
+ label: 'process.exit / kill',
98
+ pattern: /\bprocess\.(exit|kill|abort)\s*\(/,
99
+ },
100
+ {
101
+ category: 'global-mutation',
102
+ label: 'process.env mutation',
103
+ pattern: /\bprocess\.env\.[A-Z_][A-Z0-9_]*\s*=/,
104
+ },
105
+ {
106
+ category: 'global-mutation',
107
+ label: 'prototype pollution',
108
+ pattern: /\bObject\.prototype\b.*=/,
109
+ },
110
+ {
111
+ category: 'dynamic-codegen',
112
+ label: 'eval()',
113
+ pattern: /(?<![A-Za-z0-9_$])eval\s*\(/,
114
+ },
115
+ {
116
+ category: 'dynamic-codegen',
117
+ label: 'new Function()',
118
+ pattern: /\bnew\s+Function\s*\(/,
119
+ },
120
+ {
121
+ category: 'dynamic-require',
122
+ label: 'require(variable)',
123
+ pattern: /\brequire\s*\(\s*(?!['"`])/,
124
+ },
125
+ {
126
+ category: 'dynamic-require',
127
+ label: 'import(variable)',
128
+ pattern: /(?<![.\w])import\s*\(\s*(?!['"`])/,
129
+ },
130
+ {
131
+ category: 'network',
132
+ label: 'fetch()',
133
+ pattern: /(?<![A-Za-z0-9_$])fetch\s*\(/,
134
+ },
135
+ {
136
+ category: 'network',
137
+ label: 'http(s).request',
138
+ pattern: /\b(https?)\.(request|get)\s*\(/,
139
+ },
140
+ {
141
+ category: 'network',
142
+ label: 'net.connect / Socket',
143
+ pattern: /\b(net\.connect|tls\.connect|new\s+net\.Socket)\b/,
144
+ },
145
+ {
146
+ category: 'network',
147
+ label: 'dgram',
148
+ pattern: /\brequire\s*\(\s*['"](?:node:)?dgram['"]/,
149
+ },
150
+ {
151
+ category: 'fs-write',
152
+ label: 'fs.writeFile / writeFileSync',
153
+ pattern: /\bfs\.(writeFile|writeFileSync|appendFile|appendFileSync|unlink|unlinkSync|rm|rmSync)\b/,
154
+ },
155
+ {
156
+ category: 'fs-read',
157
+ label: 'fs.readFile / readFileSync',
158
+ pattern: /\bfs\.(readFile|readFileSync|readdir|readdirSync|stat|statSync)\b/,
159
+ },
160
+ ];
161
+
162
+ // Obfuscation heuristic: base64 / hex decode feeding into eval or Function.
163
+ const OBFUSCATION_PATTERN =
164
+ /Buffer\.from\s*\([^)]*['"](?:base64|hex)['"]\s*\)\s*\.toString\s*\([^)]*\)[\s\S]{0,80}?(eval|Function)\s*\(/;
165
+
166
+ // ─── File walker — picks up everything reachable from overrides ────────
167
+
168
+ function listOverrideJsFiles(manifestPath: string): string[] {
169
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as { overrides?: Record<string, unknown> };
170
+ if (!manifest.overrides) return [];
171
+ const base = dirname(manifestPath);
172
+ const out = new Set<string>();
173
+ for (const value of Object.values(manifest.overrides)) {
174
+ let rel: string | null = null;
175
+ if (typeof value === 'string') rel = value;
176
+ else if (value && typeof value === 'object' && 'path' in value && typeof (value as { path: unknown }).path === 'string') {
177
+ rel = (value as { path: string }).path;
178
+ }
179
+ if (!rel) continue;
180
+ const abs = resolve(base, rel);
181
+ if (existsSync(abs)) out.add(abs);
182
+ }
183
+ // Best-effort: also scan sibling scripts/ tree, since overrides commonly
184
+ // require() helpers from there.
185
+ for (const candidate of ['scripts']) {
186
+ const dir = join(base, candidate);
187
+ if (existsSync(dir)) {
188
+ try {
189
+ walk(dir, out);
190
+ } catch {
191
+ // Ignore individual unreadable files.
192
+ }
193
+ }
194
+ }
195
+ return [...out];
196
+ }
197
+
198
+ function walk(dir: string, into: Set<string>): void {
199
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
200
+ const { readdirSync, statSync } = require('node:fs') as typeof import('node:fs');
201
+ for (const entry of readdirSync(dir)) {
202
+ const abs = join(dir, entry);
203
+ let st;
204
+ try { st = statSync(abs); } catch { continue; }
205
+ if (st.isDirectory()) walk(abs, into);
206
+ else if (st.isFile() && /\.(?:m|c)?js$/.test(entry)) into.add(abs);
207
+ }
208
+ }
209
+
210
+ // ─── Scanner ───────────────────────────────────────────────────────────
211
+
212
+ function scanFile(file: string): TaintFinding[] {
213
+ const source = readFileSync(file, 'utf-8');
214
+ const findings: TaintFinding[] = [];
215
+ // Per-line scan keeps line numbers honest.
216
+ const lines = source.split('\n');
217
+ for (let i = 0; i < lines.length; i += 1) {
218
+ const line = lines[i];
219
+ for (const rule of PATTERNS) {
220
+ if (rule.pattern.test(line)) {
221
+ findings.push({
222
+ api: rule.label,
223
+ category: rule.category,
224
+ file,
225
+ line: i + 1,
226
+ excerpt: line.trim().slice(0, 200),
227
+ });
228
+ }
229
+ }
230
+ }
231
+ // Whole-file scan for obfuscation pattern (may span lines).
232
+ if (OBFUSCATION_PATTERN.test(source)) {
233
+ findings.push({
234
+ api: 'base64/hex → eval|Function',
235
+ category: 'obfuscation',
236
+ file,
237
+ line: 1,
238
+ excerpt: '<obfuscation pattern across multiple lines>',
239
+ });
240
+ }
241
+ return findings;
242
+ }
243
+
244
+ // ─── Classification ────────────────────────────────────────────────────
245
+
246
+ const ELEVATED_CATEGORIES = new Set<TaintCategory>([
247
+ 'shell-exec',
248
+ 'process-control',
249
+ 'dynamic-codegen',
250
+ 'dynamic-require',
251
+ 'fs-write',
252
+ 'global-mutation',
253
+ ]);
254
+
255
+ const HOSTILE_REQUIRES = new Set<TaintCategory>([
256
+ 'obfuscation',
257
+ ]);
258
+
259
+ function classify(findings: TaintFinding[]): TaintLevel {
260
+ if (findings.length === 0) return 'clean';
261
+ const cats = new Set(findings.map((f) => f.category));
262
+ if ([...cats].some((c) => HOSTILE_REQUIRES.has(c))) return 'hostile';
263
+ // Hostile also: elevated + network combined.
264
+ const hasElevated = [...cats].some((c) => ELEVATED_CATEGORIES.has(c));
265
+ const hasNetwork = cats.has('network');
266
+ if (hasElevated && hasNetwork) return 'hostile';
267
+ if (hasElevated || hasNetwork) return 'elevated';
268
+ return 'clean'; // only fs-read on its own is fine.
269
+ }
270
+
271
+ // ─── Public API ────────────────────────────────────────────────────────
272
+
273
+ export function analyzeOverrideTaint(manifestPath: string): TaintResult {
274
+ const files = listOverrideJsFiles(manifestPath);
275
+ const findings: TaintFinding[] = [];
276
+ for (const f of files) findings.push(...scanFile(f));
277
+ return {
278
+ level: classify(findings),
279
+ findings,
280
+ files,
281
+ };
282
+ }
283
+
284
+ /** Format a result as a single CLI-friendly block. */
285
+ export function formatTaintResult(result: TaintResult): string {
286
+ const lines: string[] = [];
287
+ lines.push(`Tier: extended (override JS present)`);
288
+ lines.push(`Risk level: ${result.level}`);
289
+ lines.push(`Files scanned: ${result.files.length}`);
290
+ if (result.findings.length === 0) {
291
+ lines.push('No flagged APIs detected.');
292
+ return lines.join('\n');
293
+ }
294
+ // Group by category for a tighter report.
295
+ const byCat = new Map<TaintCategory, TaintFinding[]>();
296
+ for (const f of result.findings) {
297
+ const arr = byCat.get(f.category) ?? [];
298
+ arr.push(f);
299
+ byCat.set(f.category, arr);
300
+ }
301
+ for (const [cat, items] of byCat) {
302
+ lines.push(` ${cat}: ${items.length} occurrence(s)`);
303
+ for (const f of items.slice(0, 5)) {
304
+ lines.push(` ${f.file}:${f.line} ${f.api}`);
305
+ }
306
+ if (items.length > 5) lines.push(` …and ${items.length - 5} more`);
307
+ }
308
+ return lines.join('\n');
309
+ }
@@ -0,0 +1,235 @@
1
+ /**
2
+ * PTY + terminal-screen adapter for the spec driver.
3
+ *
4
+ * Spawns a PTY, feeds bytes into a TerminalScreen (ghostty-vt when available,
5
+ * xterm fallback otherwise) so a visible-screen snapshot is always available,
6
+ * and exposes a small hook surface for the SpecDriver to consume:
7
+ *
8
+ * init({ pid }) — PTY spawned
9
+ * on_pty_data(chunk) — raw PTY byte chunk received
10
+ * on_screen_changed(snapshot) — coalesced visible-screen change
11
+ * on_exit({ exitCode }) — PTY exited
12
+ * tick() — periodic tick (if tickIntervalMs > 0)
13
+ */
14
+ 'use strict';
15
+
16
+ import { TerminalScreen } from '../../cli-adapters/terminal-screen.js';
17
+ import type { PtyTransportFactory } from '../../cli-adapters/pty-transport.js';
18
+ import type { PtyRuntimeTransport } from '../../cli-adapters/pty-transport.js';
19
+ import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from '@adhdev/session-host-core';
20
+
21
+ export type { PtyTransportFactory };
22
+
23
+ export interface TerminalAdapterOpts {
24
+ binary: string;
25
+ args?: string[];
26
+ cwd?: string;
27
+ env?: Record<string, string>;
28
+ /**
29
+ * When true, `env` is already a COMPLETE, sanitized environment (the spawn
30
+ * planner merged + stripped process.env already) and must be passed to the
31
+ * PTY verbatim — NOT overlaid on top of process.env. Overlaying would
32
+ * re-introduce the npm_/PNPM_/parent-session keys the planner explicitly
33
+ * stripped, so the spec path's spawn env would diverge from the legacy
34
+ * path's. Defaults to false (legacy overlay behaviour) for any caller that
35
+ * still passes a partial env.
36
+ */
37
+ envIsComplete?: boolean;
38
+ cols?: number;
39
+ rows?: number;
40
+ /** Coalesce screen snapshots: emit on_screen_changed at most this often. */
41
+ screenChangeDebounceMs?: number;
42
+ tickIntervalMs?: number;
43
+ transportFactory?: PtyTransportFactory;
44
+ }
45
+
46
+ export interface TerminalAdapterHandlers {
47
+ init?(info: { pid: number }): void;
48
+ on_pty_data?(chunk: string): void;
49
+ on_screen_changed?(snapshot: string): void;
50
+ on_exit?(info: { exitCode: number }): void;
51
+ tick?(): void;
52
+ }
53
+
54
+ /**
55
+ * One entry in the PTY input/output event timeline (debug-only). Captured at
56
+ * the single common point every spec@4 provider funnels through — this adapter
57
+ * — so the Spec Debug Snapshot can answer "what input / output preceded a status
58
+ * transition?". Observation only; nothing here feeds the FSM decision.
59
+ */
60
+ export interface SpecPtyEvent {
61
+ /** Wall-clock ms. */
62
+ ts: number;
63
+ kind: 'spawn' | 'input' | 'output' | 'resize' | 'cursor' | 'exit';
64
+ /** Human-readable, control-char-escaped, length-capped preview. */
65
+ content: string;
66
+ /** Raw byte length before truncation (output/input only). */
67
+ bytes?: number;
68
+ }
69
+
70
+ const MAX_PTY_EVENTS = 300;
71
+ const EVENT_CONTENT_CAP = 240;
72
+
73
+ /** Escape control characters into a visible form so the timeline is readable
74
+ * (CR/LF/ESC/tab become \r \n \x1b \t; other C0 controls become \xNN). */
75
+ function escapeControl(text: string): string {
76
+ // eslint-disable-next-line no-control-regex
77
+ return String(text).replace(/[\x00-\x1f\x7f]/g, (ch) => {
78
+ const code = ch.charCodeAt(0);
79
+ if (ch === '\r') return '\\r';
80
+ if (ch === '\n') return '\\n';
81
+ if (ch === '\t') return '\\t';
82
+ if (code === 0x1b) return '\\x1b';
83
+ return '\\x' + code.toString(16).padStart(2, '0');
84
+ });
85
+ }
86
+
87
+ function capPreview(text: string): string {
88
+ return text.length > EVENT_CONTENT_CAP ? text.slice(0, EVENT_CONTENT_CAP) + `…(+${text.length - EVENT_CONTENT_CAP})` : text;
89
+ }
90
+
91
+ export class TerminalAdapter {
92
+ private rows: number;
93
+ private cols: number;
94
+ private readonly screenDebounceMs: number;
95
+ private readonly tickIntervalMs: number;
96
+ private readonly factory: PtyTransportFactory;
97
+ private screen: TerminalScreen;
98
+ private pty: PtyRuntimeTransport | null = null;
99
+ private screenTimer: ReturnType<typeof setTimeout> | null = null;
100
+ private tickTimer: ReturnType<typeof setInterval> | null = null;
101
+ private lastScreen = '';
102
+ /** Debug-only ring buffer of PTY input/output/resize/cursor events. */
103
+ private events: SpecPtyEvent[] = [];
104
+ private lastCursorKey = '';
105
+
106
+ constructor(
107
+ private readonly opts: TerminalAdapterOpts,
108
+ private readonly handlers: TerminalAdapterHandlers,
109
+ ) {
110
+ this.cols = opts.cols ?? DEFAULT_SESSION_HOST_COLS;
111
+ this.rows = opts.rows ?? DEFAULT_SESSION_HOST_ROWS;
112
+ this.screenDebounceMs = opts.screenChangeDebounceMs ?? 80;
113
+ this.tickIntervalMs = opts.tickIntervalMs ?? 0;
114
+ // Import NodePtyTransportFactory lazily to avoid loading node-pty in
115
+ // environments that don't need it (tests, fixture runners) — only when
116
+ // no transport factory was injected. Doing it unconditionally pulled in
117
+ // the node-pty module (and broke source-level test runs) even when a
118
+ // fake factory was supplied.
119
+ if (opts.transportFactory) {
120
+ this.factory = opts.transportFactory;
121
+ } else {
122
+ const { NodePtyTransportFactory } = require('../../cli-adapters/pty-transport.js');
123
+ this.factory = new NodePtyTransportFactory();
124
+ }
125
+ this.screen = new TerminalScreen(this.rows, this.cols);
126
+ }
127
+
128
+ start(): void {
129
+ const env = this.opts.envIsComplete
130
+ ? ((this.opts.env ?? {}) as Record<string, string>)
131
+ : ({ ...process.env, ...(this.opts.env ?? {}) } as Record<string, string>);
132
+ this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
133
+ cwd: this.opts.cwd ?? process.cwd(),
134
+ env,
135
+ cols: this.cols,
136
+ rows: this.rows,
137
+ });
138
+ this.recordEvent('spawn', `${this.opts.binary} (${this.cols}x${this.rows})`);
139
+ this.handlers.init?.({ pid: this.pty.pid });
140
+ this.pty.onData((chunk) => this.onChunk(chunk));
141
+ this.pty.onExit((info) => {
142
+ this.stopTimers();
143
+ this.recordEvent('exit', `exitCode=${typeof info.exitCode === 'number' ? info.exitCode : 0}`);
144
+ this.handlers.on_exit?.({ exitCode: typeof info.exitCode === 'number' ? info.exitCode : 0 });
145
+ this.pty = null;
146
+ });
147
+ if (this.tickIntervalMs > 0) {
148
+ this.tickTimer = setInterval(() => this.handlers.tick?.(), this.tickIntervalMs);
149
+ }
150
+ }
151
+
152
+ resize(cols: number, rows: number): void {
153
+ this.cols = cols; this.rows = rows;
154
+ this.recordEvent('resize', `${cols}x${rows}`);
155
+ this.pty?.resize(cols, rows);
156
+ this.screen.resize(rows, cols);
157
+ }
158
+
159
+ snapshot(): string {
160
+ return this.lastScreen || this.computeScreen();
161
+ }
162
+
163
+ /**
164
+ * Full-buffer snapshot including scrollback history. Unlike snapshot()
165
+ * (visible viewport only), this survives a tall prompt whose top has
166
+ * scrolled off-screen — used for content-pattern extraction (modal
167
+ * buttons / approval anchors), NOT for cursor-relative conditions.
168
+ */
169
+ snapshotWithScrollback(): string {
170
+ return this.screen.getTextWithScrollback();
171
+ }
172
+
173
+ getCursorPosition(): { row: number; col: number } {
174
+ const pos = this.screen.getCursorPosition();
175
+ return { row: pos.row, col: pos.col };
176
+ }
177
+
178
+ send_keys(text: string): void {
179
+ this.recordEvent('input', capPreview(escapeControl(text)), text.length);
180
+ this.pty?.write(text);
181
+ }
182
+
183
+ /** Debug-only: most-recent PTY input/output/resize/cursor events, oldest
184
+ * first. Pure observation — never consulted by the FSM. */
185
+ getEventTimeline(limit = MAX_PTY_EVENTS): SpecPtyEvent[] {
186
+ const n = Math.max(0, Math.min(limit, this.events.length));
187
+ return this.events.slice(this.events.length - n);
188
+ }
189
+
190
+ private recordEvent(kind: SpecPtyEvent['kind'], content: string, bytes?: number): void {
191
+ const ev: SpecPtyEvent = { ts: Date.now(), kind, content };
192
+ if (typeof bytes === 'number') ev.bytes = bytes;
193
+ this.events.push(ev);
194
+ if (this.events.length > MAX_PTY_EVENTS) this.events.splice(0, this.events.length - MAX_PTY_EVENTS);
195
+ }
196
+
197
+ kill(): void {
198
+ this.stopTimers();
199
+ try { this.pty?.kill(); } catch { /* ignore */ }
200
+ this.pty = null;
201
+ this.screen.dispose();
202
+ }
203
+
204
+ private onChunk(chunk: string): void {
205
+ this.recordEvent('output', capPreview(escapeControl(chunk)), chunk.length);
206
+ try { this.handlers.on_pty_data?.(chunk); } catch { /* user side */ }
207
+ this.screen.write(chunk);
208
+ // Coalesce snapshot emission — rapid bursts shouldn't fire 200x.
209
+ if (this.screenTimer) return;
210
+ this.screenTimer = setTimeout(() => {
211
+ this.screenTimer = null;
212
+ const snap = this.computeScreen();
213
+ // Record cursor movement at the (debounced) screen-change boundary
214
+ // rather than per output chunk, so the timeline isn't flooded.
215
+ const cur = this.screen.getCursorPosition();
216
+ const curKey = `${cur.row},${cur.col}`;
217
+ if (curKey !== this.lastCursorKey) {
218
+ this.lastCursorKey = curKey;
219
+ this.recordEvent('cursor', `(${cur.row},${cur.col})`);
220
+ }
221
+ if (snap === this.lastScreen) return;
222
+ this.lastScreen = snap;
223
+ try { this.handlers.on_screen_changed?.(snap); } catch { /* user side */ }
224
+ }, this.screenDebounceMs);
225
+ }
226
+
227
+ private computeScreen(): string {
228
+ return this.screen.getText();
229
+ }
230
+
231
+ private stopTimers(): void {
232
+ if (this.screenTimer) { clearTimeout(this.screenTimer); this.screenTimer = null; }
233
+ if (this.tickTimer) { clearInterval(this.tickTimer); this.tickTimer = null; }
234
+ }
235
+ }