@adhdev/daemon-core 0.9.82-rc.46 → 0.9.82-rc.460

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 (439) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +9 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/build-info.d.ts +37 -0
  4. package/dist/chat/source-machine.d.ts +166 -0
  5. package/dist/chat/source-resolver.d.ts +104 -0
  6. package/dist/chat/subscription-updates.d.ts +1 -0
  7. package/dist/cli-adapter-types.d.ts +68 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +200 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +126 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
  14. package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
  15. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  16. package/dist/cli-adapters/resolve-executable.d.ts +69 -0
  17. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  18. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  19. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  20. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  21. package/dist/commands/chat-commands-read.d.ts +7 -0
  22. package/dist/commands/chat-commands-scope.d.ts +39 -0
  23. package/dist/commands/chat-commands-shared.d.ts +33 -0
  24. package/dist/commands/chat-commands-write.d.ts +14 -0
  25. package/dist/commands/chat-commands.d.ts +10 -23
  26. package/dist/commands/cli-manager.d.ts +25 -1
  27. package/dist/commands/handler.d.ts +125 -0
  28. package/dist/commands/high-family/index.d.ts +3 -0
  29. package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
  30. package/dist/commands/high-family/mesh-events.d.ts +2 -0
  31. package/dist/commands/high-family/mesh-status.d.ts +2 -0
  32. package/dist/commands/high-family/types.d.ts +64 -0
  33. package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
  34. package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
  35. package/dist/commands/low-family/diagnostics.d.ts +2 -0
  36. package/dist/commands/low-family/index.d.ts +3 -0
  37. package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
  38. package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
  39. package/dist/commands/low-family/notification.d.ts +2 -0
  40. package/dist/commands/low-family/refine-config.d.ts +2 -0
  41. package/dist/commands/low-family/session-host.d.ts +2 -0
  42. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  43. package/dist/commands/low-family/status-meta.d.ts +2 -0
  44. package/dist/commands/low-family/types.d.ts +33 -0
  45. package/dist/commands/med-family/cli-agent.d.ts +2 -0
  46. package/dist/commands/med-family/fast-forward.d.ts +2 -0
  47. package/dist/commands/med-family/ide.d.ts +10 -0
  48. package/dist/commands/med-family/index.d.ts +3 -0
  49. package/dist/commands/med-family/mesh-crud.d.ts +48 -0
  50. package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
  51. package/dist/commands/med-family/mesh-queue.d.ts +2 -0
  52. package/dist/commands/med-family/mesh-restart.d.ts +2 -0
  53. package/dist/commands/med-family/types.d.ts +152 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router-refine.d.ts +137 -0
  56. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  57. package/dist/commands/router.d.ts +241 -12
  58. package/dist/commands/upgrade-helper.d.ts +41 -1
  59. package/dist/config/chat-history.d.ts +9 -0
  60. package/dist/config/config.d.ts +19 -0
  61. package/dist/config/mesh-config.d.ts +129 -1
  62. package/dist/config/mesh-json-config.d.ts +199 -0
  63. package/dist/config/registry-resolver.d.ts +54 -0
  64. package/dist/config/repo-settings.d.ts +77 -0
  65. package/dist/daemon/dev-server.d.ts +0 -2
  66. package/dist/detection/ide-detector.d.ts +13 -0
  67. package/dist/detection/win32-ide-version.d.ts +37 -0
  68. package/dist/git/change-impact-config.d.ts +159 -0
  69. package/dist/git/git-commands.d.ts +12 -1
  70. package/dist/git/git-diff.d.ts +6 -0
  71. package/dist/git/git-executor.d.ts +11 -0
  72. package/dist/git/git-status.d.ts +57 -0
  73. package/dist/git/git-types.d.ts +2 -50
  74. package/dist/git/git-worktree.d.ts +71 -1
  75. package/dist/git/index.d.ts +3 -1
  76. package/dist/index.d.ts +67 -15
  77. package/dist/index.js +57943 -25340
  78. package/dist/index.js.map +1 -1
  79. package/dist/index.mjs +57611 -25174
  80. package/dist/index.mjs.map +1 -1
  81. package/dist/installer.d.ts +1 -4
  82. package/dist/ipc/local-ipc-server.d.ts +91 -0
  83. package/dist/launch.d.ts +1 -1
  84. package/dist/logging/async-batch-writer.d.ts +10 -0
  85. package/dist/logging/debug-config.d.ts +16 -0
  86. package/dist/logging/log-redactor.d.ts +24 -0
  87. package/dist/logging/log-tail-reader.d.ts +81 -0
  88. package/dist/logging/logger.d.ts +1 -1
  89. package/dist/mesh/contracts.d.ts +230 -0
  90. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  91. package/dist/mesh/coordinator-registry.d.ts +59 -0
  92. package/dist/mesh/mesh-active-work.d.ts +174 -0
  93. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  94. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  95. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  96. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  97. package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
  98. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  99. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  100. package/dist/mesh/mesh-events-pending.d.ts +113 -0
  101. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  102. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  103. package/dist/mesh/mesh-events.d.ts +6 -49
  104. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  105. package/dist/mesh/mesh-host-ownership.d.ts +29 -0
  106. package/dist/mesh/mesh-init.d.ts +128 -0
  107. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  108. package/dist/mesh/mesh-ledger.d.ts +133 -1
  109. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  110. package/dist/mesh/mesh-missions.d.ts +189 -0
  111. package/dist/mesh/mesh-node-identity.d.ts +306 -0
  112. package/dist/mesh/mesh-queue-assignment.d.ts +158 -0
  113. package/dist/mesh/mesh-reconcile-loop.d.ts +80 -0
  114. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  115. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  116. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  117. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  118. package/dist/mesh/mesh-routing.d.ts +70 -0
  119. package/dist/mesh/mesh-runtime-store.d.ts +476 -0
  120. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  121. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  122. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  123. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  124. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  125. package/dist/mesh/mesh-work-queue.d.ts +318 -5
  126. package/dist/mesh/preview-freshness.d.ts +28 -0
  127. package/dist/mesh/refine-config.d.ts +216 -0
  128. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  129. package/dist/providers/acp-provider-instance.d.ts +5 -0
  130. package/dist/providers/approval-utils.d.ts +45 -0
  131. package/dist/providers/chat-message-normalization.d.ts +58 -1
  132. package/dist/providers/cli-provider-instance.d.ts +290 -3
  133. package/dist/providers/contracts.d.ts +149 -6
  134. package/dist/providers/external-sources.d.ts +71 -0
  135. package/dist/providers/manual-attendance.d.ts +79 -0
  136. package/dist/providers/native-history/antigravity-claim-registry.d.ts +28 -0
  137. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  138. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  139. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  140. package/dist/providers/native-history/constants.d.ts +12 -0
  141. package/dist/providers/native-history/dispatcher.d.ts +31 -0
  142. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  143. package/dist/providers/native-history/index.d.ts +13 -0
  144. package/dist/providers/provider-instance-manager.d.ts +29 -0
  145. package/dist/providers/provider-instance.d.ts +30 -1
  146. package/dist/providers/provider-loader.d.ts +42 -5
  147. package/dist/providers/provider-trust.d.ts +31 -0
  148. package/dist/providers/read-chat-contract.d.ts +29 -0
  149. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  150. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  151. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  152. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  153. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  154. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  155. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  156. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  157. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  158. package/dist/providers/sdk/v1/index.d.ts +30 -0
  159. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  160. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  161. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  162. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  163. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  164. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  165. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  166. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  167. package/dist/providers/spec/adapter.d.ts +98 -0
  168. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  169. package/dist/providers/spec/evaluator.d.ts +45 -0
  170. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  171. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  172. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  173. package/dist/providers/spec/fsm-types.d.ts +202 -0
  174. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  175. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  176. package/dist/providers/spec/route.d.ts +4 -0
  177. package/dist/providers/spec/types.d.ts +222 -0
  178. package/dist/providers/status-monitor.d.ts +7 -7
  179. package/dist/providers/transcript-v2.d.ts +176 -0
  180. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  181. package/dist/providers/working-dir.d.ts +17 -0
  182. package/dist/repo-mesh-types.d.ts +519 -13
  183. package/dist/runtime-defaults.d.ts +2 -0
  184. package/dist/session-host/managed-host.d.ts +64 -0
  185. package/dist/session-host/runtime-surface.d.ts +10 -16
  186. package/dist/sessions/registry.d.ts +6 -0
  187. package/dist/shared-types-extra.d.ts +2 -4
  188. package/dist/shared-types.d.ts +86 -55
  189. package/dist/status/normalize.d.ts +1 -1
  190. package/dist/status/normalize.js +1 -0
  191. package/dist/status/normalize.js.map +1 -1
  192. package/dist/status/normalize.mjs +1 -0
  193. package/dist/status/normalize.mjs.map +1 -1
  194. package/dist/status/reporter.d.ts +2 -0
  195. package/dist/status/snapshot.d.ts +26 -0
  196. package/dist/system/hash.d.ts +8 -0
  197. package/dist/system/load-better-sqlite3.d.ts +21 -0
  198. package/dist/types.d.ts +5 -0
  199. package/package.json +11 -4
  200. package/src/agent-stream/poller.ts +2 -3
  201. package/src/agent-stream/provider-adapter.ts +1 -1
  202. package/src/boot/daemon-lifecycle.ts +65 -12
  203. package/src/boot/process-hardening.ts +89 -0
  204. package/src/build-info.ts +73 -0
  205. package/src/chat/source-machine.ts +534 -0
  206. package/src/chat/source-resolver.ts +0 -0
  207. package/src/chat/subscription-updates.ts +20 -1
  208. package/src/cli-adapter-types.d.ts +3 -1
  209. package/src/cli-adapter-types.ts +68 -2
  210. package/src/cli-adapters/cli-script-runner.ts +421 -0
  211. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  212. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  213. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  214. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  215. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  216. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  217. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  218. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  219. package/src/cli-adapters/pty-transport.ts +2 -1
  220. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  221. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  222. package/src/cli-adapters/resolve-executable.ts +204 -0
  223. package/src/cli-adapters/session-host-transport.ts +2 -1
  224. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  225. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  226. package/src/cli-adapters/terminal-screen.ts +16 -81
  227. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  228. package/src/commands/chat-commands-read.ts +2488 -0
  229. package/src/commands/chat-commands-scope.ts +54 -0
  230. package/src/commands/chat-commands-shared.ts +114 -0
  231. package/src/commands/chat-commands-write.ts +891 -0
  232. package/src/commands/chat-commands.ts +19 -1841
  233. package/src/commands/cli-manager.ts +596 -27
  234. package/src/commands/handler.ts +845 -2
  235. package/src/commands/high-family/index.ts +28 -0
  236. package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
  237. package/src/commands/high-family/mesh-events.ts +89 -0
  238. package/src/commands/high-family/mesh-status.ts +822 -0
  239. package/src/commands/high-family/types.ts +80 -0
  240. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  241. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  242. package/src/commands/low-family/diagnostics.ts +57 -0
  243. package/src/commands/low-family/index.ts +37 -0
  244. package/src/commands/low-family/mesh-ledger.ts +62 -0
  245. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  246. package/src/commands/low-family/notification.ts +116 -0
  247. package/src/commands/low-family/refine-config.ts +106 -0
  248. package/src/commands/low-family/session-host.ts +274 -0
  249. package/src/commands/low-family/spec-providerdev.ts +217 -0
  250. package/src/commands/low-family/status-meta.ts +112 -0
  251. package/src/commands/low-family/types.ts +39 -0
  252. package/src/commands/med-family/cli-agent.ts +241 -0
  253. package/src/commands/med-family/fast-forward.ts +230 -0
  254. package/src/commands/med-family/ide.ts +163 -0
  255. package/src/commands/med-family/index.ts +37 -0
  256. package/src/commands/med-family/mesh-crud.ts +1287 -0
  257. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  258. package/src/commands/med-family/mesh-queue.ts +167 -0
  259. package/src/commands/med-family/mesh-restart.ts +92 -0
  260. package/src/commands/med-family/types.ts +153 -0
  261. package/src/commands/mesh-coordinator.ts +334 -124
  262. package/src/commands/router-refine.ts +1711 -0
  263. package/src/commands/router-worktree-cleanup.ts +870 -0
  264. package/src/commands/router.ts +1025 -4070
  265. package/src/commands/stream-commands.ts +8 -0
  266. package/src/commands/upgrade-helper.ts +310 -45
  267. package/src/config/chat-history.ts +493 -24
  268. package/src/config/config.ts +30 -0
  269. package/src/config/mesh-config.ts +619 -23
  270. package/src/config/mesh-json-config.ts +376 -0
  271. package/src/config/recent-activity.ts +8 -2
  272. package/src/config/registry-resolver.ts +100 -0
  273. package/src/config/repo-settings.ts +111 -0
  274. package/src/daemon/dev-auto-implement.ts +3 -2
  275. package/src/daemon/dev-cli-debug.ts +10 -1
  276. package/src/daemon/dev-server.ts +0 -541
  277. package/src/detection/cli-detector.ts +28 -9
  278. package/src/detection/ide-detector.ts +55 -16
  279. package/src/detection/win32-ide-version.ts +106 -0
  280. package/src/git/change-impact-config.ts +354 -0
  281. package/src/git/git-commands.ts +78 -15
  282. package/src/git/git-diff.ts +81 -11
  283. package/src/git/git-executor.ts +12 -0
  284. package/src/git/git-status.ts +767 -48
  285. package/src/git/git-types.ts +14 -62
  286. package/src/git/git-worktree.ts +261 -4
  287. package/src/git/index.ts +17 -0
  288. package/src/index.ts +200 -12
  289. package/src/installer.d.ts +1 -1
  290. package/src/installer.ts +8 -6
  291. package/src/ipc/local-ipc-server.ts +278 -0
  292. package/src/launch.d.ts +1 -1
  293. package/src/launch.ts +37 -28
  294. package/src/logging/async-batch-writer.ts +55 -0
  295. package/src/logging/command-log.ts +7 -5
  296. package/src/logging/debug-config.ts +25 -0
  297. package/src/logging/debug-trace.ts +7 -2
  298. package/src/logging/log-redactor.ts +100 -0
  299. package/src/logging/log-tail-reader.ts +341 -0
  300. package/src/logging/logger.ts +14 -7
  301. package/src/mesh/contracts.ts +469 -0
  302. package/src/mesh/coordinator-prompt.ts +536 -34
  303. package/src/mesh/coordinator-registry.ts +121 -0
  304. package/src/mesh/mesh-active-work.ts +656 -0
  305. package/src/mesh/mesh-clone-grace.ts +68 -0
  306. package/src/mesh/mesh-coordinator-config.ts +97 -0
  307. package/src/mesh/mesh-delivery-policy.ts +315 -0
  308. package/src/mesh/mesh-event-classify.ts +73 -0
  309. package/src/mesh/mesh-event-forwarding.ts +1932 -0
  310. package/src/mesh/mesh-event-trace.ts +67 -0
  311. package/src/mesh/mesh-events-coordinator.ts +32 -0
  312. package/src/mesh/mesh-events-pending.ts +766 -0
  313. package/src/mesh/mesh-events-stale.ts +440 -0
  314. package/src/mesh/mesh-events-utils.ts +443 -0
  315. package/src/mesh/mesh-events.ts +33 -1035
  316. package/src/mesh/mesh-fast-forward.ts +856 -0
  317. package/src/mesh/mesh-host-ownership.ts +111 -0
  318. package/src/mesh/mesh-init.ts +350 -0
  319. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  320. package/src/mesh/mesh-ledger.ts +873 -102
  321. package/src/mesh/mesh-magi-status.ts +223 -0
  322. package/src/mesh/mesh-missions.ts +449 -0
  323. package/src/mesh/mesh-node-identity.ts +1994 -0
  324. package/src/mesh/mesh-queue-assignment.ts +2233 -0
  325. package/src/mesh/mesh-reconcile-loop.ts +2390 -0
  326. package/src/mesh/mesh-refine-batch.ts +205 -0
  327. package/src/mesh/mesh-refine-gates.ts +1686 -0
  328. package/src/mesh/mesh-refine-status.ts +231 -0
  329. package/src/mesh/mesh-review-inbox.ts +308 -0
  330. package/src/mesh/mesh-routing.ts +291 -0
  331. package/src/mesh/mesh-runtime-store.ts +2026 -0
  332. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  333. package/src/mesh/mesh-task-inflight.ts +70 -0
  334. package/src/mesh/mesh-task-stats.ts +161 -0
  335. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  336. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  337. package/src/mesh/mesh-work-queue.ts +1281 -141
  338. package/src/mesh/preview-freshness.ts +163 -0
  339. package/src/mesh/refine-config.ts +423 -0
  340. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  341. package/src/providers/acp-provider-instance.ts +43 -10
  342. package/src/providers/approval-utils.d.ts +5 -0
  343. package/src/providers/approval-utils.ts +99 -5
  344. package/src/providers/chat-message-normalization.ts +126 -4
  345. package/src/providers/cli-provider-instance.ts +2456 -107
  346. package/src/providers/contracts.d.ts +55 -0
  347. package/src/providers/contracts.ts +160 -6
  348. package/src/providers/extension-provider-instance.ts +12 -7
  349. package/src/providers/external-sources.ts +218 -0
  350. package/src/providers/ide-provider-instance.ts +35 -12
  351. package/src/providers/manual-attendance.ts +105 -0
  352. package/src/providers/native-history/antigravity-claim-registry.ts +131 -0
  353. package/src/providers/native-history/antigravity-cli-transcript.ts +1193 -0
  354. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  355. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  356. package/src/providers/native-history/constants.ts +19 -0
  357. package/src/providers/native-history/dispatcher.ts +503 -0
  358. package/src/providers/native-history/hermes-cli-transcript.ts +260 -0
  359. package/src/providers/native-history/index.ts +30 -0
  360. package/src/providers/provider-instance-manager.ts +71 -0
  361. package/src/providers/provider-instance.ts +24 -1
  362. package/src/providers/provider-loader.ts +700 -55
  363. package/src/providers/provider-schema.ts +87 -14
  364. package/src/providers/provider-trust.ts +114 -0
  365. package/src/providers/read-chat-contract.ts +76 -16
  366. package/src/providers/sdk/README.md +49 -0
  367. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  368. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  369. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  370. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  371. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  372. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  373. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  374. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  375. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  376. package/src/providers/sdk/v1/index.ts +152 -0
  377. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  378. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  379. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  380. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +509 -0
  381. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  382. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  383. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  384. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  385. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  386. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  387. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  388. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  389. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  390. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  391. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  392. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  393. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  394. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  395. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  396. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  397. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  398. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  399. package/src/providers/sdk/v1/validators/index.ts +19 -0
  400. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  401. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  402. package/src/providers/spec/adapter.ts +246 -0
  403. package/src/providers/spec/cli-adapter.ts +1064 -0
  404. package/src/providers/spec/evaluator.ts +407 -0
  405. package/src/providers/spec/fsm-driver.ts +1528 -0
  406. package/src/providers/spec/fsm-evaluator.ts +290 -0
  407. package/src/providers/spec/fsm-loader.ts +128 -0
  408. package/src/providers/spec/fsm-types.ts +301 -0
  409. package/src/providers/spec/native-history-executor.ts +1174 -0
  410. package/src/providers/spec/pre-launch-trust.ts +104 -0
  411. package/src/providers/spec/route.ts +51 -0
  412. package/src/providers/spec/types.ts +262 -0
  413. package/src/providers/status-monitor.d.ts +7 -7
  414. package/src/providers/status-monitor.ts +37 -22
  415. package/src/providers/transcript-v2.ts +567 -0
  416. package/src/providers/types/interactive-prompt.ts +536 -0
  417. package/src/providers/version-archive.ts +64 -24
  418. package/src/providers/working-dir.ts +23 -0
  419. package/src/repo-mesh-types.ts +758 -14
  420. package/src/runtime-defaults.ts +39 -0
  421. package/src/session-host/managed-host.ts +218 -0
  422. package/src/session-host/runtime-surface.ts +20 -80
  423. package/src/sessions/registry.ts +6 -0
  424. package/src/shared-types-extra.ts +2 -4
  425. package/src/shared-types.d.ts +8 -0
  426. package/src/shared-types.ts +124 -55
  427. package/src/status/builders.ts +26 -6
  428. package/src/status/normalize.ts +2 -0
  429. package/src/status/reporter.ts +19 -1
  430. package/src/status/snapshot.ts +95 -26
  431. package/src/system/hash.ts +23 -0
  432. package/src/system/host-memory.ts +29 -12
  433. package/src/system/load-better-sqlite3.ts +68 -0
  434. package/src/types.ts +5 -0
  435. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  436. package/dist/mesh/mesh-sync.d.ts +0 -53
  437. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  438. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  439. package/src/mesh/mesh-sync.ts +0 -111
@@ -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,65 @@ 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
+
44
+ /**
45
+ * True when a button reliably identifies a tool-CONSENT modal on its own — a
46
+ * scoped permission-grant affirmative such as:
47
+ * - "Yes, allow all edits in tmp/ during this session"
48
+ * - "Yes, and don't ask again for example.com"
49
+ * - "Yes, allow reading from etc/ from this project"
50
+ * - "Always allow"
51
+ *
52
+ * These options only ever appear in a genuine approval/permission prompt; a
53
+ * /model or /mode picker ("1. Default 2. Opus 3. Sonnet") never offers a
54
+ * "grant this scope" choice. They therefore serve as a SECOND reliable
55
+ * structural anchor alongside {@link hasNegativeApprovalOption}.
56
+ *
57
+ * Why this exists (tall-diff fallback, #137): when a Write/Edit diff is tall,
58
+ * the trailing decline option ("3. No") can scroll off the bottom of the
59
+ * captured PTY frame, leaving only "1. Yes" + "2. Yes, allow … this session".
60
+ * hasNegativeApprovalOption then reads false and the auto-approve gate bails —
61
+ * a delegated worker sits forever on a modal it could safely have approved. The
62
+ * grant-scope affirmative lets the gate recognize the consent modal WITHOUT
63
+ * seeing the off-frame decline. The gate still selects the plain "Yes"
64
+ * (allow-once) via pickApprovalButton, never the broader grant, and the settle
65
+ * gate still requires a stable modal — so a half-rendered frame never fires.
66
+ * Kept deliberately narrow so no picker/confirm modal can trip it.
67
+ */
68
+ export function hasReliableApprovalAffirmative(buttons: string[] | null | undefined): boolean {
69
+ return (buttons || []).some((button) => {
70
+ const label = normalizeApprovalLabel(String(button || ''));
71
+ if (!label) return false;
72
+ // "always allow …" as a standalone grant option.
73
+ if (/^always allow\b/.test(label)) return true;
74
+ // "yes, …" scoped grants: allow / always allow / don't ask again / etc.
75
+ // (normalizeApprovalLabel strips the apostrophe, so "don't" → "don t").
76
+ if (/^yes\b/.test(label)) {
77
+ if (/\ballow\b/.test(label)) return true;
78
+ if (/\bask again\b/.test(label)) return true;
79
+ if (/\bduring this session\b/.test(label)) return true;
80
+ if (/\bfrom this project\b/.test(label)) return true;
81
+ }
82
+ return false;
83
+ });
84
+ }
85
+
27
86
  export function getApprovalPositiveHints(provider?: Pick<ProviderModule, 'approvalPositiveHints'> | null): string[] {
28
87
  const customHints = Array.isArray(provider?.approvalPositiveHints)
29
88
  ? provider.approvalPositiveHints
@@ -39,24 +98,32 @@ export function pickApprovalButton(
39
98
  ): { index: number; label: string } {
40
99
  const labels = (buttons || []).map((button) => String(button || '').trim()).filter(Boolean);
41
100
  if (labels.length === 0) {
42
- return { index: 0, label: 'Approve' };
101
+ return { index: -1, label: '' };
43
102
  }
44
103
 
45
104
  const normalizedButtons = labels.map((label) => normalizeApprovalLabel(label));
46
105
  const hints = getApprovalPositiveHints(provider);
47
106
 
48
107
  for (const hint of hints) {
49
- const exactIndex = normalizedButtons.findIndex((label) => label === hint);
108
+ const exactIndex = normalizedButtons.findIndex((label, index) => label === hint && !isNegativeApprovalLabel(labels[index]));
50
109
  if (exactIndex >= 0) return { index: exactIndex, label: labels[exactIndex] };
51
110
 
52
- const prefixIndex = normalizedButtons.findIndex((label) => label.startsWith(hint));
111
+ const prefixIndex = normalizedButtons.findIndex((label, index) => label.startsWith(hint) && !isNegativeApprovalLabel(labels[index]));
53
112
  if (prefixIndex >= 0) return { index: prefixIndex, label: labels[prefixIndex] };
54
113
 
55
- const includeIndex = normalizedButtons.findIndex((label) => label.includes(hint));
114
+ const includeIndex = normalizedButtons.findIndex((label, index) => label.includes(hint) && !isNegativeApprovalLabel(labels[index]));
56
115
  if (includeIndex >= 0) return { index: includeIndex, label: labels[includeIndex] };
57
116
  }
58
117
 
59
- return { index: 0, label: labels[0] };
118
+ return { index: -1, label: '' };
119
+ }
120
+
121
+ export function pickAutoApprovalButton(
122
+ buttons: string[] | null | undefined,
123
+ ): { index: number; label: string } {
124
+ const labels = (buttons || []).map((button) => String(button || '').trim());
125
+ const index = labels.findIndex(Boolean);
126
+ return index >= 0 ? { index, label: labels[index] } : { index: -1, label: '' };
60
127
  }
61
128
 
62
129
  export function formatAutoApprovalMessage(modalMessage?: string, buttonLabel?: string): string {
@@ -65,3 +132,30 @@ export function formatAutoApprovalMessage(modalMessage?: string, buttonLabel?: s
65
132
  if (cleanMessage) lines.push(cleanMessage);
66
133
  return lines.join('\n');
67
134
  }
135
+
136
+ /**
137
+ * Returns true when the given text (e.g. last assistant message content, or
138
+ * the tail of the PTY screen) looks like an active approval/input prompt
139
+ * rather than a completed assistant response. Used to prevent false
140
+ * idle/completion events when Claude Code surfaces a "Do you want to proceed?"
141
+ * style prompt that the PTY parser captures as an assistant turn while the
142
+ * session is still awaiting user input.
143
+ */
144
+ export function looksLikeActiveApprovalPromptText(content: string): boolean {
145
+ const text = content.trim();
146
+ if (!text || text.length > 2000) return false;
147
+ const hasApprovalQuestion = /do you want to (?:proceed|allow|run|make this edit|create)/i.test(text)
148
+ || /this command requires approval/i.test(text)
149
+ || /quick safety check/i.test(text)
150
+ || /is this a project you trust/i.test(text);
151
+ const hasNumberedChoices = /^\s*[❯›>]?\s*1[.)]\s+(?:yes|allow|proceed|run)/im.test(text)
152
+ || /^\s*1[.)]\s+yes\b/im.test(text);
153
+ if (hasApprovalQuestion && hasNumberedChoices) return true;
154
+ const lastLines = text.split(/\r?\n/).slice(-12).join('\n');
155
+ const hasDontAskAgain = /yes.*don'?t ask again/i.test(lastLines)
156
+ || /yes.*always allow/i.test(lastLines);
157
+ const hasNoOption = /^\s*[❯›>]?\s*\d+[.)]\s+no\b/im.test(lastLines);
158
+ if (hasDontAskAgain && hasNoOption) return true;
159
+ if (/what do you want to do\?/i.test(text) && /^\s*\d+[.)]\s+\S/m.test(text)) return true;
160
+ return false;
161
+ }
@@ -1,7 +1,7 @@
1
1
  import type { ChatMessage } from '../types.js';
2
2
  import { flattenContent } from './contracts.js';
3
3
 
4
- export const DEFAULT_FINAL_SUMMARY_MAX_CHARS = 4_000;
4
+ export const DEFAULT_FINAL_SUMMARY_MAX_CHARS = 16_000;
5
5
 
6
6
  export function extractFinalSummaryFromMessages(
7
7
  messages: ChatMessage[] | null | undefined,
@@ -20,20 +20,142 @@ export function extractFinalSummaryFromMessages(
20
20
  }
21
21
  }
22
22
 
23
- // Fallback: last user-facing message of any role
23
+ // Completion summaries must describe the assistant/model result. If no
24
+ // user-facing assistant/model message exists yet (for example, only the
25
+ // dispatched user prompt is visible), return empty instead of echoing the
26
+ // prompt as a misleading finalSummary.
27
+ return '';
28
+ }
29
+
30
+ export function readChatMessageTimestampMs(message: ChatMessage | null | undefined): number | undefined {
31
+ if (!message) return undefined;
32
+ const record = message as ChatMessage & Record<string, unknown>;
33
+ for (const value of [record.timestamp, record.createdAt, record.created_at, record.updatedAt, record.time, record.receivedAt]) {
34
+ if (typeof value === 'number' && Number.isFinite(value)) {
35
+ // Heuristic seconds-vs-ms detection mirrors the mesh transcript reader.
36
+ return value > 10_000_000_000 ? value : value * 1000;
37
+ }
38
+ if (typeof value === 'string' && value.trim()) {
39
+ const ms = new Date(value.trim()).getTime();
40
+ if (Number.isFinite(ms)) return ms;
41
+ }
42
+ }
43
+ return undefined;
44
+ }
45
+
46
+ function readChatMessageTimestampIso(message: ChatMessage | null | undefined): string | undefined {
47
+ const ms = readChatMessageTimestampMs(message);
48
+ return typeof ms === 'number' ? new Date(ms).toISOString() : undefined;
49
+ }
50
+
51
+ /**
52
+ * Turn-scoped variant of extractFinalSummaryFromMessages. Selects the last
53
+ * user-facing assistant/model bubble whose own timestamp is at/after the
54
+ * producing turn's start (`minTimestampMs`). This is the NOTIF Defect-B fix:
55
+ * a completion event's finalSummary must describe the turn THAT completed, not
56
+ * the prior task's last bubble. For native-source providers (claude-cli) the
57
+ * external transcript holds the ENTIRE session history filtered only by session
58
+ * start, so a completion debounce that fires before the producing turn's final
59
+ * assistant bubble has landed would otherwise echo the previous task's tail.
60
+ * A message whose timestamp predates the turn start is skipped; if no in-turn
61
+ * assistant bubble exists yet, returns '' (weak/empty) — never the stale tail.
62
+ *
63
+ * Mirrors the reconcile path's transcriptAfterDispatch guard (mesh-events-stale):
64
+ * a bubble only counts if its timestamp proves it was produced after the turn began.
65
+ * When `minTimestampMs` is undefined the behaviour is identical to the unscoped
66
+ * extractor (no turn boundary known → no filtering).
67
+ */
68
+ export function extractFinalSummaryFromMessagesAfter(
69
+ messages: ChatMessage[] | null | undefined,
70
+ minTimestampMs: number | undefined,
71
+ maxChars: number = DEFAULT_FINAL_SUMMARY_MAX_CHARS,
72
+ ): string {
73
+ if (!Array.isArray(messages) || messages.length === 0) return '';
74
+ const hasBoundary = typeof minTimestampMs === 'number' && Number.isFinite(minTimestampMs);
75
+
24
76
  for (let i = messages.length - 1; i >= 0; i--) {
25
77
  const msg = messages[i];
26
78
  if (!msg) continue;
79
+ if (hasBoundary) {
80
+ // A bubble carrying a timestamp BEFORE the producing turn's start belongs to
81
+ // a prior task — skip it. A bubble with no parseable timestamp cannot be
82
+ // proven stale, so it is kept (the unscoped fallback) rather than dropped.
83
+ const ts = readChatMessageTimestampMs(msg);
84
+ if (typeof ts === 'number' && ts < (minTimestampMs as number)) continue;
85
+ }
27
86
  const classification = classifyChatMessageVisibility(msg);
28
- if (classification.isUserFacing) {
87
+ if (classification.isUserFacing && (msg.role === 'assistant' || msg.role === 'model')) {
29
88
  const text = flattenContent(msg.content).trim();
30
89
  if (text) return text.slice(0, maxChars);
31
90
  }
32
91
  }
33
-
34
92
  return '';
35
93
  }
36
94
 
95
+ /**
96
+ * Like extractFinalSummaryFromMessages but also returns the ISO timestamp of the
97
+ * selected final assistant/model message. Completion reconciliation needs the
98
+ * timestamp to prove the transcript was produced AFTER the dispatch — without it
99
+ * reconcileDirectDispatchCompletionFromTranscript rejects non-JSON summaries as
100
+ * "transcript_not_proven_after_dispatch". The summary selection is identical so the
101
+ * timestamp always belongs to the message whose text became the summary.
102
+ */
103
+ export function extractFinalAssistantSummaryEvidence(
104
+ messages: ChatMessage[] | null | undefined,
105
+ maxChars: number = DEFAULT_FINAL_SUMMARY_MAX_CHARS,
106
+ ): { finalSummary: string; transcriptMessageAt?: string } {
107
+ const turnEnd = selectFinalAssistantTurnEndMessage(messages);
108
+ if (!turnEnd) return { finalSummary: '' };
109
+ return {
110
+ finalSummary: flattenContent(turnEnd.content).trim().slice(0, maxChars),
111
+ transcriptMessageAt: readChatMessageTimestampIso(turnEnd),
112
+ };
113
+ }
114
+
115
+ /**
116
+ * EARLYNOTIFY-GATEBYPASS (a)/(b) — the shared turn-finality selector for the completion
117
+ * final-assistant judgement, so the ~duplicated "which bubble is the turn's final answer"
118
+ * logic is decided ONE way (UNIFY A-6).
119
+ *
120
+ * Returns the message that qualifies as the turn's FINAL assistant bubble, or null when the
121
+ * transcript does not (yet) prove a turn end. The rule is a NON-EMPTY LATEST user-facing
122
+ * assistant/model bubble:
123
+ * - Scanning from the end, the FIRST user-facing assistant/model bubble encountered IS the
124
+ * turn-end candidate. If it is EMPTY (a streaming placeholder / mid-turn narration whose
125
+ * text has not landed), the turn is still in flight → return null. Crucially we do NOT walk
126
+ * back past that empty bubble to promote an EARLIER assistant narration to "final" (the
127
+ * Defect-B walk-back).
128
+ * - Trailing activity/internal bubbles (tool/thought/status) are skipped — they are not the
129
+ * assistant's user-facing answer.
130
+ * - A trailing user-facing USER message (a freshly dispatched task with no reply yet) means the
131
+ * assistant did not have the last word — no earlier bubble is promoted here; callers that must
132
+ * still reach a prior turn's tail use the timestamp-scoped extractor instead.
133
+ *
134
+ * A bare snapshot-idle with an arbitrary non-empty tail therefore does NOT qualify as a turn end;
135
+ * only a genuine latest-assistant bubble does. Turn-finality signals that live OUTSIDE the
136
+ * transcript (a committed generating→idle FSM transition, a self-attributing final_summary_json,
137
+ * or a continuous-idle streak) are enforced by the callers (the CLI completion gate, the reconcile
138
+ * grace gate) on top of this structural check.
139
+ */
140
+ export function selectFinalAssistantTurnEndMessage(
141
+ messages: ChatMessage[] | null | undefined,
142
+ ): ChatMessage | null {
143
+ if (!Array.isArray(messages) || messages.length === 0) return null;
144
+ for (let i = messages.length - 1; i >= 0; i--) {
145
+ const msg = messages[i];
146
+ if (!msg) continue;
147
+ const classification = classifyChatMessageVisibility(msg);
148
+ if (!classification.isUserFacing) continue; // skip tool/thought/status activity + internal
149
+ if (msg.role === 'assistant' || msg.role === 'model') {
150
+ // The latest user-facing assistant bubble: it is the turn end iff it has real text.
151
+ return flattenContent(msg.content).trim() ? msg : null;
152
+ }
153
+ // A user (or other role) had the last user-facing word → the assistant turn is not complete.
154
+ return null;
155
+ }
156
+ return null;
157
+ }
158
+
37
159
  export const BUILTIN_CHAT_MESSAGE_KINDS = ['standard', 'thought', 'tool', 'terminal', 'system'] as const;
38
160
 
39
161
  export type BuiltinChatMessageKind = typeof BUILTIN_CHAT_MESSAGE_KINDS[number];