@adhdev/daemon-core 0.9.82-rc.41 → 0.9.82-rc.410

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 (417) 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 +14 -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 +2 -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 +116 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router.d.ts +256 -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 +77 -1
  60. package/dist/config/mesh-json-config.d.ts +299 -0
  61. package/dist/daemon/dev-server.d.ts +0 -2
  62. package/dist/detection/ide-detector.d.ts +13 -0
  63. package/dist/detection/win32-ide-version.d.ts +37 -0
  64. package/dist/git/change-impact-config.d.ts +159 -0
  65. package/dist/git/git-commands.d.ts +11 -1
  66. package/dist/git/git-diff.d.ts +6 -0
  67. package/dist/git/git-executor.d.ts +11 -0
  68. package/dist/git/git-status.d.ts +57 -0
  69. package/dist/git/git-types.d.ts +2 -50
  70. package/dist/git/git-worktree.d.ts +71 -1
  71. package/dist/git/index.d.ts +3 -1
  72. package/dist/index.d.ts +57 -13
  73. package/dist/index.js +46445 -17229
  74. package/dist/index.js.map +1 -1
  75. package/dist/index.mjs +46052 -16978
  76. package/dist/index.mjs.map +1 -1
  77. package/dist/installer.d.ts +1 -4
  78. package/dist/ipc/local-ipc-server.d.ts +91 -0
  79. package/dist/launch.d.ts +1 -1
  80. package/dist/logging/async-batch-writer.d.ts +10 -0
  81. package/dist/logging/log-redactor.d.ts +24 -0
  82. package/dist/logging/log-tail-reader.d.ts +81 -0
  83. package/dist/logging/logger.d.ts +1 -1
  84. package/dist/mesh/contracts.d.ts +164 -0
  85. package/dist/mesh/coordinator-prompt.d.ts +89 -0
  86. package/dist/mesh/coordinator-registry.d.ts +59 -0
  87. package/dist/mesh/mesh-active-work.d.ts +174 -0
  88. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  89. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  90. package/dist/mesh/mesh-event-classify.d.ts +5 -0
  91. package/dist/mesh/mesh-event-forwarding.d.ts +19 -0
  92. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  93. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  94. package/dist/mesh/mesh-events-pending.d.ts +55 -0
  95. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  96. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  97. package/dist/mesh/mesh-events.d.ts +6 -49
  98. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  99. package/dist/mesh/mesh-host-ownership.d.ts +9 -0
  100. package/dist/mesh/mesh-init.d.ts +86 -0
  101. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  102. package/dist/mesh/mesh-ledger.d.ts +77 -1
  103. package/dist/mesh/mesh-missions.d.ts +164 -0
  104. package/dist/mesh/mesh-node-identity.d.ts +289 -0
  105. package/dist/mesh/mesh-queue-assignment.d.ts +95 -0
  106. package/dist/mesh/mesh-reconcile-loop.d.ts +65 -0
  107. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  108. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  109. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  110. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  111. package/dist/mesh/mesh-routing.d.ts +70 -0
  112. package/dist/mesh/mesh-runtime-store.d.ts +447 -0
  113. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  114. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  115. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  116. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  117. package/dist/mesh/mesh-work-queue.d.ts +281 -5
  118. package/dist/mesh/preview-freshness.d.ts +18 -0
  119. package/dist/mesh/refine-config.d.ts +216 -0
  120. package/dist/mesh/worktree-bootstrap-config.d.ts +145 -0
  121. package/dist/providers/acp-provider-instance.d.ts +5 -0
  122. package/dist/providers/approval-utils.d.ts +20 -0
  123. package/dist/providers/chat-message-normalization.d.ts +31 -1
  124. package/dist/providers/cli-provider-instance.d.ts +197 -3
  125. package/dist/providers/contracts.d.ts +139 -6
  126. package/dist/providers/external-sources.d.ts +71 -0
  127. package/dist/providers/manual-attendance.d.ts +63 -0
  128. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
  129. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  130. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  131. package/dist/providers/native-history/constants.d.ts +12 -0
  132. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  133. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  134. package/dist/providers/native-history/index.d.ts +13 -0
  135. package/dist/providers/provider-instance-manager.d.ts +14 -0
  136. package/dist/providers/provider-instance.d.ts +23 -1
  137. package/dist/providers/provider-loader.d.ts +26 -4
  138. package/dist/providers/provider-trust.d.ts +31 -0
  139. package/dist/providers/read-chat-contract.d.ts +29 -0
  140. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  141. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  142. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  143. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  144. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  145. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  146. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  147. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  148. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  149. package/dist/providers/sdk/v1/index.d.ts +30 -0
  150. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  151. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  152. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  153. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  154. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  155. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  156. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  157. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  158. package/dist/providers/spec/adapter.d.ts +91 -0
  159. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  160. package/dist/providers/spec/evaluator.d.ts +45 -0
  161. package/dist/providers/spec/fsm-driver.d.ts +407 -0
  162. package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
  163. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  164. package/dist/providers/spec/fsm-types.d.ts +174 -0
  165. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  166. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  167. package/dist/providers/spec/route.d.ts +4 -0
  168. package/dist/providers/spec/types.d.ts +222 -0
  169. package/dist/providers/status-monitor.d.ts +7 -7
  170. package/dist/providers/transcript-v2.d.ts +176 -0
  171. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  172. package/dist/providers/working-dir.d.ts +17 -0
  173. package/dist/repo-mesh-types.d.ts +420 -13
  174. package/dist/runtime-defaults.d.ts +2 -0
  175. package/dist/sessions/registry.d.ts +6 -0
  176. package/dist/shared-types-extra.d.ts +2 -4
  177. package/dist/shared-types.d.ts +59 -2
  178. package/dist/status/normalize.d.ts +1 -1
  179. package/dist/status/normalize.js +1 -0
  180. package/dist/status/normalize.js.map +1 -1
  181. package/dist/status/normalize.mjs +1 -0
  182. package/dist/status/normalize.mjs.map +1 -1
  183. package/dist/status/reporter.d.ts +2 -0
  184. package/dist/status/snapshot.d.ts +26 -0
  185. package/dist/system/hash.d.ts +8 -0
  186. package/dist/system/load-better-sqlite3.d.ts +21 -0
  187. package/dist/types.d.ts +5 -0
  188. package/package.json +7 -3
  189. package/src/agent-stream/poller.ts +2 -3
  190. package/src/agent-stream/provider-adapter.ts +1 -1
  191. package/src/boot/daemon-lifecycle.ts +63 -12
  192. package/src/boot/process-hardening.ts +89 -0
  193. package/src/build-info.ts +73 -0
  194. package/src/chat/source-machine.ts +534 -0
  195. package/src/chat/source-resolver.ts +0 -0
  196. package/src/chat/subscription-updates.ts +20 -1
  197. package/src/cli-adapter-types.d.ts +3 -1
  198. package/src/cli-adapter-types.ts +68 -2
  199. package/src/cli-adapters/cli-script-runner.ts +421 -0
  200. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  201. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  202. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  203. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  204. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  205. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  206. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  207. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  208. package/src/cli-adapters/pty-transport.ts +2 -1
  209. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  210. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  211. package/src/cli-adapters/resolve-executable.ts +90 -0
  212. package/src/cli-adapters/session-host-transport.ts +2 -1
  213. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  214. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  215. package/src/cli-adapters/terminal-screen.ts +16 -81
  216. package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
  217. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  218. package/src/commands/chat-commands-read.ts +2327 -0
  219. package/src/commands/chat-commands-scope.ts +54 -0
  220. package/src/commands/chat-commands-shared.ts +114 -0
  221. package/src/commands/chat-commands-write.ts +891 -0
  222. package/src/commands/chat-commands.ts +19 -1841
  223. package/src/commands/cli-manager.ts +527 -26
  224. package/src/commands/handler.ts +841 -2
  225. package/src/commands/high-family/index.ts +28 -0
  226. package/src/commands/high-family/mesh-coordinator-launch.ts +673 -0
  227. package/src/commands/high-family/mesh-events.ts +80 -0
  228. package/src/commands/high-family/mesh-status.ts +678 -0
  229. package/src/commands/high-family/types.ts +76 -0
  230. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  231. package/src/commands/low-family/daemon-lifecycle.ts +107 -0
  232. package/src/commands/low-family/diagnostics.ts +57 -0
  233. package/src/commands/low-family/index.ts +37 -0
  234. package/src/commands/low-family/mesh-ledger.ts +62 -0
  235. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  236. package/src/commands/low-family/notification.ts +116 -0
  237. package/src/commands/low-family/refine-config.ts +106 -0
  238. package/src/commands/low-family/session-host.ts +274 -0
  239. package/src/commands/low-family/spec-providerdev.ts +217 -0
  240. package/src/commands/low-family/status-meta.ts +112 -0
  241. package/src/commands/low-family/types.ts +39 -0
  242. package/src/commands/med-family/cli-agent.ts +238 -0
  243. package/src/commands/med-family/fast-forward.ts +230 -0
  244. package/src/commands/med-family/ide.ts +163 -0
  245. package/src/commands/med-family/index.ts +37 -0
  246. package/src/commands/med-family/mesh-crud.ts +874 -0
  247. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  248. package/src/commands/med-family/mesh-queue.ts +131 -0
  249. package/src/commands/med-family/mesh-restart.ts +92 -0
  250. package/src/commands/med-family/types.ts +120 -0
  251. package/src/commands/mesh-coordinator.ts +334 -124
  252. package/src/commands/router.ts +2516 -3221
  253. package/src/commands/stream-commands.ts +8 -0
  254. package/src/commands/upgrade-helper.ts +310 -45
  255. package/src/config/chat-history.ts +483 -24
  256. package/src/config/config.ts +12 -0
  257. package/src/config/mesh-config.ts +353 -22
  258. package/src/config/mesh-json-config.ts +617 -0
  259. package/src/config/recent-activity.ts +8 -2
  260. package/src/daemon/dev-auto-implement.ts +3 -2
  261. package/src/daemon/dev-cli-debug.ts +10 -1
  262. package/src/daemon/dev-server.ts +0 -541
  263. package/src/detection/cli-detector.ts +28 -9
  264. package/src/detection/ide-detector.ts +55 -16
  265. package/src/detection/win32-ide-version.ts +106 -0
  266. package/src/git/change-impact-config.ts +354 -0
  267. package/src/git/git-commands.ts +59 -15
  268. package/src/git/git-diff.ts +81 -11
  269. package/src/git/git-executor.ts +12 -0
  270. package/src/git/git-status.ts +767 -48
  271. package/src/git/git-types.ts +14 -62
  272. package/src/git/git-worktree.ts +261 -4
  273. package/src/git/index.ts +17 -0
  274. package/src/index.ts +171 -12
  275. package/src/installer.d.ts +1 -1
  276. package/src/installer.ts +8 -6
  277. package/src/ipc/local-ipc-server.ts +278 -0
  278. package/src/launch.d.ts +1 -1
  279. package/src/launch.ts +37 -28
  280. package/src/logging/async-batch-writer.ts +55 -0
  281. package/src/logging/command-log.ts +7 -5
  282. package/src/logging/log-redactor.ts +100 -0
  283. package/src/logging/log-tail-reader.ts +341 -0
  284. package/src/logging/logger.ts +14 -7
  285. package/src/mesh/contracts.ts +338 -0
  286. package/src/mesh/coordinator-prompt.ts +381 -33
  287. package/src/mesh/coordinator-registry.ts +121 -0
  288. package/src/mesh/mesh-active-work.ts +645 -0
  289. package/src/mesh/mesh-coordinator-config.ts +97 -0
  290. package/src/mesh/mesh-delivery-policy.ts +315 -0
  291. package/src/mesh/mesh-event-classify.ts +51 -0
  292. package/src/mesh/mesh-event-forwarding.ts +1773 -0
  293. package/src/mesh/mesh-event-trace.ts +67 -0
  294. package/src/mesh/mesh-events-coordinator.ts +31 -0
  295. package/src/mesh/mesh-events-pending.ts +590 -0
  296. package/src/mesh/mesh-events-stale.ts +389 -0
  297. package/src/mesh/mesh-events-utils.ts +443 -0
  298. package/src/mesh/mesh-events.ts +32 -1035
  299. package/src/mesh/mesh-fast-forward.ts +843 -0
  300. package/src/mesh/mesh-host-ownership.ts +73 -0
  301. package/src/mesh/mesh-init.ts +260 -0
  302. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  303. package/src/mesh/mesh-ledger.ts +596 -102
  304. package/src/mesh/mesh-missions.ts +322 -0
  305. package/src/mesh/mesh-node-identity.ts +1887 -0
  306. package/src/mesh/mesh-queue-assignment.ts +1738 -0
  307. package/src/mesh/mesh-reconcile-loop.ts +1726 -0
  308. package/src/mesh/mesh-refine-batch.ts +205 -0
  309. package/src/mesh/mesh-refine-gates.ts +1666 -0
  310. package/src/mesh/mesh-refine-status.ts +231 -0
  311. package/src/mesh/mesh-review-inbox.ts +307 -0
  312. package/src/mesh/mesh-routing.ts +291 -0
  313. package/src/mesh/mesh-runtime-store.ts +1836 -0
  314. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  315. package/src/mesh/mesh-task-stats.ts +161 -0
  316. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  317. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  318. package/src/mesh/mesh-work-queue.ts +1205 -141
  319. package/src/mesh/preview-freshness.ts +118 -0
  320. package/src/mesh/refine-config.ts +423 -0
  321. package/src/mesh/worktree-bootstrap-config.ts +369 -0
  322. package/src/providers/acp-provider-instance.ts +43 -10
  323. package/src/providers/approval-utils.d.ts +5 -0
  324. package/src/providers/approval-utils.ts +57 -5
  325. package/src/providers/chat-message-normalization.ts +92 -4
  326. package/src/providers/cli-provider-instance.ts +1865 -104
  327. package/src/providers/contracts.d.ts +55 -0
  328. package/src/providers/contracts.ts +150 -6
  329. package/src/providers/extension-provider-instance.ts +12 -7
  330. package/src/providers/external-sources.ts +218 -0
  331. package/src/providers/ide-provider-instance.ts +35 -12
  332. package/src/providers/manual-attendance.ts +85 -0
  333. package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
  334. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  335. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  336. package/src/providers/native-history/constants.ts +19 -0
  337. package/src/providers/native-history/dispatcher.ts +339 -0
  338. package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
  339. package/src/providers/native-history/index.ts +30 -0
  340. package/src/providers/provider-instance-manager.ts +30 -0
  341. package/src/providers/provider-instance.ts +19 -1
  342. package/src/providers/provider-loader.ts +668 -50
  343. package/src/providers/provider-schema.ts +87 -14
  344. package/src/providers/provider-trust.ts +114 -0
  345. package/src/providers/read-chat-contract.ts +76 -16
  346. package/src/providers/sdk/README.md +49 -0
  347. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  348. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  349. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  350. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  351. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  352. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  353. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  354. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  355. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  356. package/src/providers/sdk/v1/index.ts +152 -0
  357. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  358. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  359. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  360. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
  361. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  362. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  363. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  364. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  365. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  366. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  367. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  368. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  369. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  370. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  371. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  372. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  373. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  374. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  375. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  376. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  377. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  378. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  379. package/src/providers/sdk/v1/validators/index.ts +19 -0
  380. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  381. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  382. package/src/providers/spec/adapter.ts +235 -0
  383. package/src/providers/spec/cli-adapter.ts +1056 -0
  384. package/src/providers/spec/evaluator.ts +407 -0
  385. package/src/providers/spec/fsm-driver.ts +1304 -0
  386. package/src/providers/spec/fsm-evaluator.ts +272 -0
  387. package/src/providers/spec/fsm-loader.ts +120 -0
  388. package/src/providers/spec/fsm-types.ts +273 -0
  389. package/src/providers/spec/native-history-executor.ts +1128 -0
  390. package/src/providers/spec/pre-launch-trust.ts +104 -0
  391. package/src/providers/spec/route.ts +51 -0
  392. package/src/providers/spec/types.ts +262 -0
  393. package/src/providers/status-monitor.d.ts +7 -7
  394. package/src/providers/status-monitor.ts +37 -22
  395. package/src/providers/transcript-v2.ts +567 -0
  396. package/src/providers/types/interactive-prompt.ts +536 -0
  397. package/src/providers/version-archive.ts +64 -24
  398. package/src/providers/working-dir.ts +23 -0
  399. package/src/repo-mesh-types.ts +629 -14
  400. package/src/runtime-defaults.ts +39 -0
  401. package/src/sessions/registry.ts +6 -0
  402. package/src/shared-types-extra.ts +2 -4
  403. package/src/shared-types.d.ts +8 -0
  404. package/src/shared-types.ts +64 -1
  405. package/src/status/builders.ts +26 -6
  406. package/src/status/normalize.ts +2 -0
  407. package/src/status/reporter.ts +19 -1
  408. package/src/status/snapshot.ts +95 -26
  409. package/src/system/hash.ts +23 -0
  410. package/src/system/host-memory.ts +29 -12
  411. package/src/system/load-better-sqlite3.ts +68 -0
  412. package/src/types.ts +5 -0
  413. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  414. package/dist/mesh/mesh-sync.d.ts +0 -53
  415. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  416. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  417. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,369 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { join, resolve as pathResolve } from 'path';
3
+ import { execFile, execFileSync } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
5
+ import { promisify } from 'node:util';
6
+ import * as yaml from 'js-yaml';
7
+ import { resolveWin32Executable } from '../cli-adapters/resolve-executable.js';
8
+ import {
9
+ isMeshConfigRecord,
10
+ normalizeMeshCommandConfig,
11
+ type MeshRefineValidationCommandPlan,
12
+ type RepoMeshRefineValidationCommandConfig,
13
+ } from './refine-config.js';
14
+ import type { MeshAsyncJobLifecycle } from '../repo-mesh-types.js';
15
+
16
+ export type WorktreeBootstrapStatus = 'ready' | 'running' | 'failed' | 'not_configured' | 'disabled' | 'stale';
17
+
18
+ export interface RepoMeshWorktreeBootstrapConfig {
19
+ version: 1;
20
+ enabled?: boolean;
21
+ runOnClone?: boolean;
22
+ required?: boolean;
23
+ commands?: RepoMeshRefineValidationCommandConfig[];
24
+ staleInputs?: string[];
25
+ }
26
+
27
+ export interface WorktreeBootstrapState extends MeshAsyncJobLifecycle {
28
+ status: WorktreeBootstrapStatus;
29
+ required: boolean;
30
+ configSource?: string;
31
+ configSourceType?: 'repo_file' | 'mesh_policy' | 'unavailable' | 'invalid';
32
+ lastCommand?: string;
33
+ exitCode?: number | null;
34
+ commandsRun?: Array<Record<string, unknown>>;
35
+ staleInputs?: string[];
36
+ /**
37
+ * M2-1: sha256 per staleInputs path recorded when the bootstrap reached
38
+ * 'ready'. evaluateWorktreeBootstrapState compares current file hashes
39
+ * against this to detect staleness (e.g. base merge changed a lockfile).
40
+ * Missing files hash to the literal 'absent'.
41
+ */
42
+ staleInputsDigest?: Record<string, string>;
43
+ /** M2-1: why an evaluated state resolved to stale (digest_mismatch | never_ran). */
44
+ staleReason?: string;
45
+ }
46
+
47
+ // Fix (3) safety net: a worktree node whose bootstrap state is stuck 'running' far longer than
48
+ // any real bootstrap (observed ~2m8s) is almost certainly one whose terminal-state stamp never
49
+ // reached this daemon's mesh view — the claim/dispatch defer guards would otherwise gate it
50
+ // forever. This backstop lets a dispatch through ONLY when BOTH hold: the 'running' state is
51
+ // older than WORKTREE_BOOTSTRAP_STALE_RUNNING_MS AND the node's working tree is git-clean. The
52
+ // clean co-requirement is the real guard — a genuinely in-progress bootstrap (npm install /
53
+ // native-addon repair) leaves the tree mid-build, so a clean tree means the bootstrap work has
54
+ // settled. The threshold is floored well above the observed real bootstrap so a slow-but-live
55
+ // bootstrap is never downgraded. Conservative by design: when clean-ness cannot be verified (no
56
+ // local workspace on disk, or git errors) it returns false and the gate stays closed.
57
+ export const WORKTREE_BOOTSTRAP_STALE_RUNNING_MS = 10 * 60 * 1000;
58
+
59
+ export function isWorktreeBootstrapStaleRunning(
60
+ node: { worktreeBootstrap?: { status?: string; startedAt?: string; updatedAt?: string; completedAt?: string }; workspace?: string } | undefined,
61
+ nowMs: number = Date.now(),
62
+ ): boolean {
63
+ const wb = node?.worktreeBootstrap;
64
+ if (!wb || wb.status !== 'running') return false;
65
+ const startedRaw = wb.updatedAt || wb.startedAt;
66
+ if (!startedRaw) return false;
67
+ const startedMs = Date.parse(startedRaw);
68
+ if (!Number.isFinite(startedMs)) return false;
69
+ if (nowMs - startedMs <= WORKTREE_BOOTSTRAP_STALE_RUNNING_MS) return false;
70
+ const workspace = typeof node?.workspace === 'string' ? node.workspace.trim() : '';
71
+ if (!workspace || !existsSync(workspace)) return false; // only verifiable for a local workspace
72
+ try {
73
+ const out = execFileSync(resolveWin32Executable('git'), ['status', '--porcelain'], {
74
+ cwd: workspace,
75
+ encoding: 'utf8',
76
+ timeout: 10_000,
77
+ windowsHide: true,
78
+ });
79
+ return String(out).trim() === '';
80
+ } catch {
81
+ return false; // cannot verify clean → stay conservative (gate remains closed)
82
+ }
83
+ }
84
+
85
+ export interface WorktreeBootstrapConfigLoadResult {
86
+ config?: RepoMeshWorktreeBootstrapConfig;
87
+ source: string;
88
+ sourceType: 'repo_file' | 'mesh_policy' | 'unavailable' | 'invalid';
89
+ path?: string;
90
+ error?: string;
91
+ }
92
+
93
+ export const MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS = [
94
+ '.adhdev/worktree_bootstrap.json',
95
+ '.adhdev/worktree_bootstrap.yaml',
96
+ '.adhdev/worktree_bootstrap.yml',
97
+ '.adhdev/worktree-bootstrap.json',
98
+ '.adhdev/worktree-bootstrap.yaml',
99
+ '.adhdev/worktree-bootstrap.yml',
100
+ ];
101
+
102
+ export const MESH_WORKTREE_BOOTSTRAP_CONFIG_SCHEMA = {
103
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
104
+ title: 'ADHDev Repo Mesh Worktree Bootstrap Config',
105
+ type: 'object',
106
+ additionalProperties: false,
107
+ required: ['version'],
108
+ properties: {
109
+ version: { const: 1 },
110
+ enabled: { type: 'boolean', default: true },
111
+ runOnClone: { type: 'boolean', default: true },
112
+ required: { type: 'boolean', default: true },
113
+ staleInputs: { type: 'array', maxItems: 16, items: { type: 'string', minLength: 1 } },
114
+ commands: {
115
+ type: 'array',
116
+ minItems: 1,
117
+ maxItems: 4,
118
+ items: {
119
+ type: 'object',
120
+ additionalProperties: false,
121
+ required: ['command'],
122
+ properties: {
123
+ command: { type: 'string', minLength: 1 },
124
+ args: { type: 'array', items: { type: 'string' } },
125
+ category: { enum: ['typecheck', 'test', 'lint', 'build', 'custom'] },
126
+ cwd: { type: 'string' },
127
+ timeoutMs: { type: 'number', minimum: 1000, maximum: 600000 },
128
+ outputLimitBytes: { type: 'number', minimum: 1024, maximum: 1048576 },
129
+ env: { type: 'object', additionalProperties: { type: 'string' } },
130
+ },
131
+ },
132
+ },
133
+ },
134
+ } as const;
135
+
136
+ const DEFAULT_TIMEOUT_MS = 120_000;
137
+ const DEFAULT_OUTPUT_LIMIT_BYTES = 128 * 1024;
138
+ const OUTPUT_SUMMARY_CHARS = 2_000;
139
+
140
+ function parseConfigText(path: string, text: string): unknown {
141
+ if (/\.json$/i.test(path)) return JSON.parse(text);
142
+ return yaml.load(text);
143
+ }
144
+
145
+ function truncateOutput(value: unknown): string {
146
+ const text = typeof value === 'string' ? value : value == null ? '' : String(value);
147
+ if (text.length <= OUTPUT_SUMMARY_CHARS) return text;
148
+ return `${text.slice(0, OUTPUT_SUMMARY_CHARS)}\n[truncated ${text.length - OUTPUT_SUMMARY_CHARS} chars]`;
149
+ }
150
+
151
+ export function validateMeshWorktreeBootstrapConfig(config: unknown, source = 'inline'): {
152
+ valid: boolean;
153
+ errors: string[];
154
+ commands: MeshRefineValidationCommandPlan[];
155
+ rejectedCommands: Array<Record<string, unknown>>;
156
+ } {
157
+ const errors: string[] = [];
158
+ const commands: MeshRefineValidationCommandPlan[] = [];
159
+ const rejectedCommands: Array<Record<string, unknown>> = [];
160
+ if (!isMeshConfigRecord(config)) return { valid: false, errors: ['config must be an object'], commands, rejectedCommands };
161
+ if (config.version !== 1) errors.push('version must be 1');
162
+ if (config.enabled !== undefined && typeof config.enabled !== 'boolean') errors.push('enabled must be a boolean when provided');
163
+ if (config.runOnClone !== undefined && typeof config.runOnClone !== 'boolean') errors.push('runOnClone must be a boolean when provided');
164
+ if (config.required !== undefined && typeof config.required !== 'boolean') errors.push('required must be a boolean when provided');
165
+ if (config.staleInputs !== undefined && (!Array.isArray(config.staleInputs) || !config.staleInputs.every(input => typeof input === 'string' && input.trim()))) {
166
+ errors.push('staleInputs must be an array of non-empty strings when provided');
167
+ }
168
+ if (config.commands !== undefined && !Array.isArray(config.commands)) errors.push('commands must be an array');
169
+ if (Array.isArray(config.commands)) {
170
+ config.commands.forEach((entry, index) => {
171
+ const normalized = normalizeMeshCommandConfig(entry, `${source}:commands[${index}]`);
172
+ if (normalized.command) commands.push(normalized.command);
173
+ if (normalized.rejected) rejectedCommands.push(normalized.rejected);
174
+ });
175
+ }
176
+ if (config.enabled !== false && config.runOnClone !== false && commands.length === 0) errors.push('commands must contain at least one command when bootstrap is enabled');
177
+ if (rejectedCommands.length) errors.push('one or more bootstrap commands are invalid');
178
+ return { valid: errors.length === 0, errors, commands, rejectedCommands };
179
+ }
180
+
181
+ export function loadMeshWorktreeBootstrapConfig(mesh: any, workspace: string): WorktreeBootstrapConfigLoadResult {
182
+ const inline = mesh?.worktreeBootstrapConfig || mesh?.policy?.worktreeBootstrapConfig || mesh?.policy?.worktreeBootstrap;
183
+ if (inline !== undefined) {
184
+ const validation = validateMeshWorktreeBootstrapConfig(inline, 'mesh.policy.worktreeBootstrapConfig');
185
+ if (!validation.valid) return { source: 'mesh.policy.worktreeBootstrapConfig', sourceType: 'invalid', error: String(validation.rejectedCommands[0]?.reason || validation.errors.join('; ')) };
186
+ return { config: inline as RepoMeshWorktreeBootstrapConfig, source: 'mesh.policy.worktreeBootstrapConfig', sourceType: 'mesh_policy' };
187
+ }
188
+ for (const relative of MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS) {
189
+ const configPath = join(workspace, relative);
190
+ if (!existsSync(configPath)) continue;
191
+ try {
192
+ const parsed = parseConfigText(configPath, readFileSync(configPath, 'utf-8'));
193
+ const validation = validateMeshWorktreeBootstrapConfig(parsed, relative);
194
+ if (!validation.valid) return { source: relative, sourceType: 'invalid', path: configPath, error: String(validation.rejectedCommands[0]?.reason || validation.errors.join('; ')) };
195
+ return { config: parsed as RepoMeshWorktreeBootstrapConfig, source: relative, sourceType: 'repo_file', path: configPath };
196
+ } catch (error: any) {
197
+ return { source: relative, sourceType: 'invalid', path: configPath, error: error?.message || String(error) };
198
+ }
199
+ }
200
+ return { source: 'unavailable', sourceType: 'unavailable', error: `No worktree bootstrap config found. Checked: ${MESH_WORKTREE_BOOTSTRAP_CONFIG_LOCATIONS.join(', ')}` };
201
+ }
202
+
203
+ /** M2-1: hash staleInputs files so 'ready' can be invalidated when they change. */
204
+ export function computeStaleInputsDigest(workspace: string, staleInputs: string[] | undefined): Record<string, string> {
205
+ const digest: Record<string, string> = {};
206
+ for (const relative of staleInputs ?? []) {
207
+ const filePath = join(workspace, relative);
208
+ try {
209
+ digest[relative] = createHash('sha256').update(readFileSync(filePath)).digest('hex');
210
+ } catch {
211
+ digest[relative] = 'absent';
212
+ }
213
+ }
214
+ return digest;
215
+ }
216
+
217
+ /**
218
+ * M2-1: the official bootstrap state contract. Resolves the effective state
219
+ * for a node workspace from config presence + the persisted last-run state +
220
+ * a staleInputs digest comparison. Read-only — never runs commands.
221
+ *
222
+ * ready — last run succeeded and staleInputs are unchanged
223
+ * stale — never ran, or a staleInputs file changed since 'ready'
224
+ * running/failed — persisted lifecycle state passes through
225
+ * not_configured / disabled / (invalid → failed) — from config resolution
226
+ */
227
+ export function evaluateWorktreeBootstrapState(mesh: any, workspace: string, persisted?: WorktreeBootstrapState | null): WorktreeBootstrapState {
228
+ const loaded = loadMeshWorktreeBootstrapConfig(mesh, workspace);
229
+ if (!loaded.config) {
230
+ return { status: 'not_configured', required: false, configSource: loaded.source, configSourceType: loaded.sourceType, error: loaded.error };
231
+ }
232
+ const required = loaded.config.required !== false;
233
+ if (loaded.config.enabled === false || loaded.config.runOnClone === false) {
234
+ return { status: 'disabled', required, configSource: loaded.path || loaded.source, configSourceType: loaded.sourceType };
235
+ }
236
+ if (loaded.sourceType === 'invalid') {
237
+ return { status: 'failed', required, configSource: loaded.path || loaded.source, configSourceType: 'invalid', error: loaded.error };
238
+ }
239
+ if (persisted?.status === 'running') return { ...persisted, required };
240
+ if (persisted?.status === 'failed') return { ...persisted, required };
241
+ if (persisted?.status === 'ready') {
242
+ const staleInputs = loaded.config.staleInputs ?? persisted.staleInputs ?? [];
243
+ if (staleInputs.length > 0 && persisted.staleInputsDigest) {
244
+ const current = computeStaleInputsDigest(workspace, staleInputs);
245
+ const changed = staleInputs.filter(p => current[p] !== persisted.staleInputsDigest![p]);
246
+ if (changed.length > 0) {
247
+ return {
248
+ ...persisted,
249
+ status: 'stale',
250
+ required,
251
+ staleReason: `digest_mismatch: ${changed.join(', ')}`,
252
+ };
253
+ }
254
+ }
255
+ return { ...persisted, required };
256
+ }
257
+ return {
258
+ status: 'stale',
259
+ required,
260
+ configSource: loaded.path || loaded.source,
261
+ configSourceType: loaded.sourceType,
262
+ staleInputs: loaded.config.staleInputs,
263
+ staleReason: 'never_ran',
264
+ };
265
+ }
266
+
267
+ export async function runMeshWorktreeBootstrap(mesh: any, workspace: string): Promise<WorktreeBootstrapState> {
268
+ const loaded = loadMeshWorktreeBootstrapConfig(mesh, workspace);
269
+ if (!loaded.config) {
270
+ return { status: 'not_configured', required: false, configSource: loaded.source, configSourceType: loaded.sourceType, error: loaded.error };
271
+ }
272
+ const required = loaded.config.required !== false;
273
+ if (loaded.config.enabled === false || loaded.config.runOnClone === false) {
274
+ return { status: 'disabled', required, configSource: loaded.path || loaded.source, configSourceType: loaded.sourceType };
275
+ }
276
+ const validation = validateMeshWorktreeBootstrapConfig(loaded.config, loaded.source);
277
+ if (!validation.valid) {
278
+ return { status: 'failed', required, configSource: loaded.path || loaded.source, configSourceType: 'invalid', error: String(validation.rejectedCommands[0]?.reason || validation.errors.join('; ')), commandsRun: [] };
279
+ }
280
+
281
+ const execFileAsync = promisify(execFile);
282
+ const state: WorktreeBootstrapState = {
283
+ status: 'running',
284
+ required,
285
+ configSource: loaded.path || loaded.source,
286
+ configSourceType: loaded.sourceType,
287
+ startedAt: new Date().toISOString(),
288
+ commandsRun: [],
289
+ staleInputs: loaded.config.staleInputs,
290
+ };
291
+ const staleInputPaths = loaded.config.staleInputs ?? [];
292
+ // Snapshot which staleInputs files are absent at bootstrap start.
293
+ // Files already present before we start are not interference signals.
294
+ const initiallyAbsent = staleInputPaths.filter(p => !existsSync(join(workspace, p)));
295
+ for (const command of validation.commands) {
296
+ // Check if any initially-absent staleInputs files appeared since bootstrap started
297
+ // (indicates another process modified the environment mid-run).
298
+ if (initiallyAbsent.length > 0) {
299
+ const appearedNow = initiallyAbsent.filter(p => existsSync(join(workspace, p)));
300
+ if (appearedNow.length > 0) {
301
+ state.status = 'stale';
302
+ state.completedAt = new Date().toISOString();
303
+ state.error = `Bootstrap interrupted: staleInputs files appeared during run: ${appearedNow.join(', ')}`;
304
+ return state;
305
+ }
306
+ }
307
+ const cwd = command.cwd ? pathResolve(workspace, command.cwd) : workspace;
308
+ const startedAt = Date.now();
309
+ state.lastCommand = command.displayCommand;
310
+ // On win32 a bare npm/npx/tsc is a .cmd shim that libuv's spawn search
311
+ // (which appends only .com/.exe) cannot resolve → spawn ENOENT. Resolve
312
+ // to an absolute path first (no-op on non-win32 / already-absolute).
313
+ const resolvedCommand = resolveWin32Executable(command.command);
314
+ try {
315
+ const result = await execFileAsync(resolvedCommand, command.args, {
316
+ cwd,
317
+ encoding: 'utf8',
318
+ timeout: command.timeoutMs || DEFAULT_TIMEOUT_MS,
319
+ maxBuffer: command.outputLimitBytes || DEFAULT_OUTPUT_LIMIT_BYTES,
320
+ env: { ...process.env, CI: process.env.CI || '1', ...(command.env || {}) },
321
+ windowsHide: true,
322
+ });
323
+ state.commandsRun?.push({
324
+ command: command.command,
325
+ args: command.args,
326
+ displayCommand: command.displayCommand,
327
+ category: command.category,
328
+ source: command.source,
329
+ cwd,
330
+ passed: true,
331
+ durationMs: Date.now() - startedAt,
332
+ exitCode: 0,
333
+ stdout: truncateOutput(result.stdout),
334
+ stderr: truncateOutput(result.stderr),
335
+ });
336
+ } catch (error: any) {
337
+ const exitCode = typeof error?.code === 'number' ? error.code : null;
338
+ state.status = 'failed';
339
+ state.exitCode = exitCode;
340
+ state.error = error?.message || String(error);
341
+ state.completedAt = new Date().toISOString();
342
+ state.commandsRun?.push({
343
+ command: command.command,
344
+ args: command.args,
345
+ displayCommand: command.displayCommand,
346
+ category: command.category,
347
+ source: command.source,
348
+ cwd,
349
+ passed: false,
350
+ durationMs: Date.now() - startedAt,
351
+ exitCode,
352
+ signal: typeof error?.signal === 'string' ? error.signal : null,
353
+ timedOut: error?.killed === true || /timed out/i.test(String(error?.message || '')),
354
+ stdout: truncateOutput(error?.stdout),
355
+ stderr: truncateOutput(error?.stderr || error?.message),
356
+ });
357
+ return state;
358
+ }
359
+ }
360
+ state.status = 'ready';
361
+ state.exitCode = 0;
362
+ state.completedAt = new Date().toISOString();
363
+ // M2-1: record staleInputs hashes so evaluateWorktreeBootstrapState can
364
+ // invalidate this 'ready' when an input (e.g. lockfile) changes later.
365
+ if (staleInputPaths.length > 0) {
366
+ state.staleInputsDigest = computeStaleInputsDigest(workspace, staleInputPaths);
367
+ }
368
+ return state;
369
+ }
@@ -51,7 +51,9 @@ import { normalizeContent, flattenContent, normalizeInputEnvelope } from './cont
51
51
  import { assertProviderSupportsDeclaredInput, getEffectiveMessageInputSupport } from './provider-input-support.js';
52
52
  import type { ProviderInstance, ProviderState, AcpProviderState, ProviderErrorReason, ProviderEvent, InstanceContext, SessionModalState } from './provider-instance.js';
53
53
  import { StatusMonitor } from './status-monitor.js';
54
+ import { ManualAttendanceTracker } from './manual-attendance.js';
54
55
  import { buildLegacyModelModeSummaryMetadata } from './summary-metadata.js';
56
+ import { workingDirBasename } from './working-dir.js';
55
57
  import {
56
58
  buildAssistantChatMessage,
57
59
  buildChatMessage,
@@ -287,6 +289,8 @@ export class AcpProviderInstance implements ProviderInstance {
287
289
  private partialBlocks: ContentBlock[] = [];
288
290
  /** Tool calls collected during current turn */
289
291
  private turnToolCalls: ToolCallInfo[] = [];
292
+ /** Guard: prevent concurrent sendPrompt calls from racing on shared state */
293
+ private _sendPromptInFlight = false;
290
294
 
291
295
  // Error tracking
292
296
  private errorMessage: string | null = null;
@@ -326,8 +330,8 @@ export class AcpProviderInstance implements ProviderInstance {
326
330
  this.settings = context.settings || {};
327
331
  this.monitor.updateConfig({
328
332
  approvalAlert: this.settings.approvalAlert !== false,
329
- longGeneratingAlert: this.settings.longGeneratingAlert !== false,
330
- longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180,
333
+ noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
334
+ noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180,
331
335
  });
332
336
 
333
337
  await this.spawnAgent();
@@ -343,7 +347,7 @@ export class AcpProviderInstance implements ProviderInstance {
343
347
  }
344
348
 
345
349
  getSessionModalState(): SessionModalState {
346
- const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
350
+ const dirName = workingDirBasename(this.workingDir);
347
351
  return {
348
352
  id: this.instanceId,
349
353
  status: this.currentStatus,
@@ -356,7 +360,7 @@ export class AcpProviderInstance implements ProviderInstance {
356
360
  }
357
361
 
358
362
  getState(): AcpProviderState {
359
- const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
363
+ const dirName = workingDirBasename(this.workingDir);
360
364
 
361
365
  const recentMessages = normalizeChatMessages(this.messages.map(m => {
362
366
  const content = m.content;
@@ -671,8 +675,8 @@ export class AcpProviderInstance implements ProviderInstance {
671
675
  this.settings = { ...this.settings, ...newSettings };
672
676
  this.monitor.updateConfig({
673
677
  approvalAlert: this.settings.approvalAlert !== false,
674
- longGeneratingAlert: this.settings.longGeneratingAlert !== false,
675
- longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180,
678
+ noProgressAlert: (this.settings.noProgressAlert ?? this.settings.longGeneratingAlert) !== false,
679
+ noProgressThresholdSec: this.settings.noProgressThresholdSec ?? this.settings.longGeneratingThresholdSec ?? 180,
676
680
  });
677
681
  this.log.info(`[${this.type}] Settings updated: ${Object.keys(newSettings).join(', ')}`);
678
682
  }
@@ -842,7 +846,12 @@ export class AcpProviderInstance implements ProviderInstance {
842
846
  }
843
847
 
844
848
  // ─── Auto-approve: skip user confirmation ───
845
- if (this.settings.autoApprove !== false) {
849
+ // Held while a human is actively attending this session (manual
850
+ // attendance) so they can decide the permission themselves; falls
851
+ // through to the waiting_approval manual path below. A background
852
+ // worker is never attended, so its delegated auto-approve fires
853
+ // as before.
854
+ if (this.settings.autoApprove !== false && !this.manualAttendance.isAttended()) {
846
855
  const toolTitle = tc.title || tc.toolCallId || 'tool call';
847
856
  this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
848
857
  this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
@@ -1002,7 +1011,11 @@ export class AcpProviderInstance implements ProviderInstance {
1002
1011
  }
1003
1012
  } catch (e: any) {
1004
1013
  this.log.warn(`[${this.type}] session/new failed: ${e?.message}`);
1005
- this.currentStatus = 'idle';
1014
+ if (!this.errorReason) {
1015
+ this.errorReason = 'init_failed';
1016
+ this.errorMessage = `ACP session creation failed: ${e?.message}`;
1017
+ }
1018
+ this.currentStatus = 'error';
1006
1019
  }
1007
1020
  }
1008
1021
 
@@ -1012,6 +1025,12 @@ export class AcpProviderInstance implements ProviderInstance {
1012
1025
  return;
1013
1026
  }
1014
1027
 
1028
+ if (this._sendPromptInFlight) {
1029
+ this.log.warn(`[${this.type}] sendPrompt already in flight — dropping concurrent request`);
1030
+ throw new Error('ACP sendPrompt already in flight');
1031
+ }
1032
+ this._sendPromptInFlight = true;
1033
+
1015
1034
  // Build prompt content
1016
1035
  const promptParts: any[] = contentBlocks && contentBlocks.length > 0
1017
1036
  ? contentBlocks.map((b) => {
@@ -1098,6 +1117,8 @@ export class AcpProviderInstance implements ProviderInstance {
1098
1117
  this.finalizeAssistantMessage();
1099
1118
  this.currentStatus = 'idle';
1100
1119
  this.detectStatusTransition();
1120
+ } finally {
1121
+ this._sendPromptInFlight = false;
1101
1122
  }
1102
1123
  }
1103
1124
 
@@ -1113,6 +1134,17 @@ export class AcpProviderInstance implements ProviderInstance {
1113
1134
 
1114
1135
  private permissionResolvers: ((approved: boolean) => void)[] = [];
1115
1136
 
1137
+ // Provider-common manual-attendance signal: while a human is actively driving
1138
+ // this session from the dashboard, auto-approve holds so they can decide on
1139
+ // the permission request themselves. Background workers are never attended →
1140
+ // delegated auto-approve is unaffected.
1141
+ private readonly manualAttendance = new ManualAttendanceTracker();
1142
+
1143
+ /** @see ProviderInstance.noteManualInteraction */
1144
+ noteManualInteraction(now = Date.now()): void {
1145
+ this.manualAttendance.note(now);
1146
+ }
1147
+
1116
1148
  async resolvePermission(approved: boolean): Promise<void> {
1117
1149
  const resolver = this.permissionResolvers.shift();
1118
1150
  if (resolver) {
@@ -1490,7 +1522,7 @@ export class AcpProviderInstance implements ProviderInstance {
1490
1522
  private detectStatusTransition(): void {
1491
1523
  const now = Date.now();
1492
1524
  const newStatus = this.currentStatus;
1493
- const dirName = this.workingDir.split('/').filter(Boolean).pop() || 'session';
1525
+ const dirName = workingDirBasename(this.workingDir);
1494
1526
  const chatTitle = `${this.provider.name} · ${dirName}`;
1495
1527
  const progressFingerprint = newStatus === 'generating'
1496
1528
  ? `${this.partialContent}::${JSON.stringify(this.partialBlocks)}::${JSON.stringify(this.activeToolCalls.map(t => ({ name: t.name, status: t.status })))}`.slice(-2000)
@@ -1518,7 +1550,8 @@ export class AcpProviderInstance implements ProviderInstance {
1518
1550
 
1519
1551
  // Monitor check
1520
1552
  const agentKey = `${this.type}:acp`;
1521
- const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint);
1553
+ const approvalPending = newStatus === 'waiting_approval';
1554
+ const monitorEvents = this.monitor.check(agentKey, newStatus, now, progressFingerprint, approvalPending);
1522
1555
  for (const me of monitorEvents) {
1523
1556
  this.pushEvent({ event: me.type, agentKey: me.agentKey, message: me.message, elapsedSec: me.elapsedSec, timestamp: me.timestamp });
1524
1557
  }
@@ -4,4 +4,9 @@ export declare function pickApprovalButton(buttons: string[] | null | undefined,
4
4
  index: number;
5
5
  label: string;
6
6
  };
7
+ export declare function pickAutoApprovalButton(buttons: string[] | null | undefined): {
8
+ index: number;
9
+ label: string;
10
+ };
11
+ export declare function hasNegativeApprovalOption(buttons: string[] | null | undefined): boolean;
7
12
  export declare function formatAutoApprovalMessage(modalMessage?: string, buttonLabel?: string): string;
@@ -24,6 +24,23 @@ function normalizeApprovalLabel(value: string): string {
24
24
  .trim();
25
25
  }
26
26
 
27
+ function isNegativeApprovalLabel(value: string): boolean {
28
+ const label = normalizeApprovalLabel(value);
29
+ return /^(no|deny|reject|cancel|skip|exit|stop)\b/.test(label)
30
+ || /\bwithout\b/.test(label)
31
+ || /\bdo not\b/.test(label);
32
+ }
33
+
34
+ /**
35
+ * True when any of the given button labels reads as a decline/negative option
36
+ * (No / Deny / Cancel / Skip / …). Used as the second half of an approval-modal
37
+ * structural anchor: a real approval modal offers BOTH an affirmative and a
38
+ * decline, which distinguishes it from a generic numbered menu or prose list.
39
+ */
40
+ export function hasNegativeApprovalOption(buttons: string[] | null | undefined): boolean {
41
+ return (buttons || []).some((button) => isNegativeApprovalLabel(String(button || '')));
42
+ }
43
+
27
44
  export function getApprovalPositiveHints(provider?: Pick<ProviderModule, 'approvalPositiveHints'> | null): string[] {
28
45
  const customHints = Array.isArray(provider?.approvalPositiveHints)
29
46
  ? provider.approvalPositiveHints
@@ -39,24 +56,32 @@ export function pickApprovalButton(
39
56
  ): { index: number; label: string } {
40
57
  const labels = (buttons || []).map((button) => String(button || '').trim()).filter(Boolean);
41
58
  if (labels.length === 0) {
42
- return { index: 0, label: 'Approve' };
59
+ return { index: -1, label: '' };
43
60
  }
44
61
 
45
62
  const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
46
63
  const hints = getApprovalPositiveHints(provider);
47
64
 
48
65
  for (const hint of hints) {
49
- const exactIndex = normalizedButtons.findIndex((label) => label === hint);
66
+ const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
50
67
  if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
51
68
 
52
- const prefixIndex = normalizedButtons.findIndex((label) => label.startsWith(hint));
69
+ const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
53
70
  if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
54
71
 
55
- const includeIndex = normalizedButtons.findIndex((label) => label.includes(hint));
72
+ const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
56
73
  if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
57
74
  }
58
75
 
59
- return { index: 0, label: labels[0] };
76
+ return { index: -1, label: '' };
77
+ }
78
+
79
+ export function pickAutoApprovalButton(
80
+ buttons: string[] | null | undefined,
81
+ ): { index: number; label: string } {
82
+ const labels = (buttons || []).map((button) => String(button || '').trim());
83
+ const index = labels.findIndex(Boolean);
84
+ return index >= 0 ? { index, label: labels[index] } : { index: -1, label: '' };
60
85
  }
61
86
 
62
87
  export function formatAutoApprovalMessage(modalMessage?: string, buttonLabel?: string): string {
@@ -65,3 +90,30 @@ export function formatAutoApprovalMessage(modalMessage?: string, buttonLabel?: s
65
90
  if (cleanMessage) lines.push(cleanMessage);
66
91
  return lines.join('\n');
67
92
  }
93
+
94
+ /**
95
+ * Returns true when the given text (e.g. last assistant message content, or
96
+ * the tail of the PTY screen) looks like an active approval/input prompt
97
+ * rather than a completed assistant response. Used to prevent false
98
+ * idle/completion events when Claude Code surfaces a "Do you want to proceed?"
99
+ * style prompt that the PTY parser captures as an assistant turn while the
100
+ * session is still awaiting user input.
101
+ */
102
+ export function looksLikeActiveApprovalPromptText(content: string): boolean {
103
+ const text = content.trim();
104
+ if (!text || text.length > 2000) return false;
105
+ const hasApprovalQuestion = /do you want to (?:proceed|allow|run|make this edit|create)/i.test(text)
106
+ || /this command requires approval/i.test(text)
107
+ || /quick safety check/i.test(text)
108
+ || /is this a project you trust/i.test(text);
109
+ const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text)
110
+ || /^\s*1[.)]\s+yes\b/im.test(text);
111
+ if (hasApprovalQuestion && hasNumberedChoices) return true;
112
+ const lastLines = text.split(/\r?\n/).slice(-12).join('\n');
113
+ const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines)
114
+ || /yes.*always allow/i.test(lastLines);
115
+ const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
116
+ if (hasDontAskAgain && hasNoOption) return true;
117
+ if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
118
+ return false;
119
+ }