@adhdev/daemon-core 0.9.82-rc.47 → 0.9.82-rc.470

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 (468) 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-aggregate-status.d.ts +24 -0
  56. package/dist/commands/router-mesh-session-owner.d.ts +59 -0
  57. package/dist/commands/router-refine.d.ts +137 -0
  58. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  59. package/dist/commands/router.d.ts +204 -15
  60. package/dist/commands/upgrade-helper.d.ts +41 -1
  61. package/dist/config/chat-history.d.ts +9 -0
  62. package/dist/config/config.d.ts +19 -0
  63. package/dist/config/mesh-config.d.ts +136 -1
  64. package/dist/config/mesh-json-config.d.ts +199 -0
  65. package/dist/config/registry-resolver.d.ts +54 -0
  66. package/dist/config/repo-settings.d.ts +77 -0
  67. package/dist/daemon/dev-server.d.ts +0 -2
  68. package/dist/detection/cli-detector.d.ts +17 -0
  69. package/dist/detection/ide-detector.d.ts +13 -0
  70. package/dist/detection/win32-ide-version.d.ts +37 -0
  71. package/dist/git/change-impact-config.d.ts +159 -0
  72. package/dist/git/git-commands.d.ts +26 -2
  73. package/dist/git/git-diff.d.ts +6 -0
  74. package/dist/git/git-executor.d.ts +11 -0
  75. package/dist/git/git-status.d.ts +57 -0
  76. package/dist/git/git-types.d.ts +2 -50
  77. package/dist/git/git-worktree.d.ts +71 -1
  78. package/dist/git/index.d.ts +3 -1
  79. package/dist/index.d.ts +70 -16
  80. package/dist/index.js +58255 -24541
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.mjs +59189 -25650
  83. package/dist/index.mjs.map +1 -1
  84. package/dist/installer.d.ts +1 -4
  85. package/dist/ipc/local-ipc-server.d.ts +91 -0
  86. package/dist/launch.d.ts +1 -1
  87. package/dist/logging/async-batch-writer.d.ts +10 -0
  88. package/dist/logging/debug-config.d.ts +16 -0
  89. package/dist/logging/log-redactor.d.ts +24 -0
  90. package/dist/logging/log-tail-reader.d.ts +81 -0
  91. package/dist/logging/logger.d.ts +1 -1
  92. package/dist/mesh/contracts.d.ts +230 -0
  93. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  94. package/dist/mesh/coordinator-registry.d.ts +59 -0
  95. package/dist/mesh/mesh-active-work.d.ts +203 -0
  96. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  97. package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
  98. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  99. package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
  100. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  101. package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
  102. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  103. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  104. package/dist/mesh/mesh-events-pending.d.ts +246 -0
  105. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  106. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  107. package/dist/mesh/mesh-events.d.ts +6 -49
  108. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  109. package/dist/mesh/mesh-host-ownership.d.ts +29 -0
  110. package/dist/mesh/mesh-init.d.ts +128 -0
  111. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  112. package/dist/mesh/mesh-ledger.d.ts +139 -1
  113. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  114. package/dist/mesh/mesh-missions.d.ts +226 -0
  115. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  116. package/dist/mesh/mesh-queue-assignment.d.ts +158 -0
  117. package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
  118. package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
  119. package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
  120. package/dist/mesh/mesh-reconcile-loop.d.ts +80 -0
  121. package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
  122. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  123. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  124. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  125. package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
  126. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  127. package/dist/mesh/mesh-routing.d.ts +70 -0
  128. package/dist/mesh/mesh-runtime-store.d.ts +508 -0
  129. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  130. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  131. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  132. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  133. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  134. package/dist/mesh/mesh-work-queue.d.ts +363 -5
  135. package/dist/mesh/preview-freshness.d.ts +28 -0
  136. package/dist/mesh/refine-config.d.ts +216 -0
  137. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  138. package/dist/providers/acp-provider-instance.d.ts +5 -0
  139. package/dist/providers/approval-utils.d.ts +46 -0
  140. package/dist/providers/chat-message-normalization.d.ts +58 -1
  141. package/dist/providers/cli-provider-effect-format.d.ts +30 -0
  142. package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
  143. package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
  144. package/dist/providers/cli-provider-instance-types.d.ts +45 -0
  145. package/dist/providers/cli-provider-instance.d.ts +340 -30
  146. package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
  147. package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
  148. package/dist/providers/contracts.d.ts +149 -6
  149. package/dist/providers/external-sources.d.ts +71 -0
  150. package/dist/providers/manual-attendance.d.ts +79 -0
  151. package/dist/providers/native-history/antigravity-claim-registry.d.ts +28 -0
  152. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  153. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  154. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  155. package/dist/providers/native-history/constants.d.ts +12 -0
  156. package/dist/providers/native-history/dispatcher.d.ts +31 -0
  157. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  158. package/dist/providers/native-history/index.d.ts +13 -0
  159. package/dist/providers/provider-instance-manager.d.ts +29 -0
  160. package/dist/providers/provider-instance.d.ts +30 -1
  161. package/dist/providers/provider-loader.d.ts +42 -5
  162. package/dist/providers/provider-trust.d.ts +31 -0
  163. package/dist/providers/read-chat-contract.d.ts +29 -0
  164. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  165. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  166. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  167. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  168. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  169. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  170. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  171. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  172. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  173. package/dist/providers/sdk/v1/index.d.ts +30 -0
  174. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  175. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  176. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  177. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  178. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  179. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  180. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  181. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  182. package/dist/providers/spec/adapter.d.ts +98 -0
  183. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  184. package/dist/providers/spec/evaluator.d.ts +45 -0
  185. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  186. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  187. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  188. package/dist/providers/spec/fsm-types.d.ts +202 -0
  189. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  190. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  191. package/dist/providers/spec/route.d.ts +4 -0
  192. package/dist/providers/spec/types.d.ts +244 -0
  193. package/dist/providers/status-monitor.d.ts +7 -7
  194. package/dist/providers/transcript-v2.d.ts +176 -0
  195. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  196. package/dist/providers/working-dir.d.ts +17 -0
  197. package/dist/repo-mesh-types.d.ts +629 -12
  198. package/dist/runtime-defaults.d.ts +2 -0
  199. package/dist/session-host/managed-host.d.ts +64 -0
  200. package/dist/session-host/runtime-surface.d.ts +10 -16
  201. package/dist/sessions/registry.d.ts +6 -0
  202. package/dist/shared-types-extra.d.ts +2 -4
  203. package/dist/shared-types.d.ts +86 -55
  204. package/dist/status/normalize.d.ts +1 -1
  205. package/dist/status/normalize.js +1 -0
  206. package/dist/status/normalize.js.map +1 -1
  207. package/dist/status/normalize.mjs +1 -0
  208. package/dist/status/normalize.mjs.map +1 -1
  209. package/dist/status/reporter.d.ts +2 -0
  210. package/dist/status/snapshot.d.ts +26 -0
  211. package/dist/system/hash.d.ts +8 -0
  212. package/dist/system/load-better-sqlite3.d.ts +21 -0
  213. package/dist/types.d.ts +5 -0
  214. package/package.json +11 -4
  215. package/src/agent-stream/poller.ts +2 -3
  216. package/src/agent-stream/provider-adapter.ts +1 -1
  217. package/src/boot/daemon-lifecycle.ts +80 -14
  218. package/src/boot/process-hardening.ts +89 -0
  219. package/src/build-info.ts +73 -0
  220. package/src/chat/source-machine.ts +534 -0
  221. package/src/chat/source-resolver.ts +0 -0
  222. package/src/chat/subscription-updates.ts +20 -1
  223. package/src/cli-adapter-types.d.ts +3 -1
  224. package/src/cli-adapter-types.ts +68 -2
  225. package/src/cli-adapters/cli-script-runner.ts +421 -0
  226. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  227. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  228. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  229. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  230. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  231. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  232. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  233. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  234. package/src/cli-adapters/pty-transport.ts +2 -1
  235. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  236. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  237. package/src/cli-adapters/resolve-executable.ts +204 -0
  238. package/src/cli-adapters/session-host-transport.ts +2 -1
  239. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  240. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  241. package/src/cli-adapters/terminal-screen.ts +16 -81
  242. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  243. package/src/commands/chat-commands-read.ts +2488 -0
  244. package/src/commands/chat-commands-scope.ts +54 -0
  245. package/src/commands/chat-commands-shared.ts +114 -0
  246. package/src/commands/chat-commands-write.ts +891 -0
  247. package/src/commands/chat-commands.ts +19 -1841
  248. package/src/commands/cli-manager.ts +596 -27
  249. package/src/commands/handler.ts +845 -2
  250. package/src/commands/high-family/index.ts +28 -0
  251. package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
  252. package/src/commands/high-family/mesh-events.ts +102 -0
  253. package/src/commands/high-family/mesh-status.ts +849 -0
  254. package/src/commands/high-family/types.ts +80 -0
  255. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  256. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  257. package/src/commands/low-family/diagnostics.ts +57 -0
  258. package/src/commands/low-family/index.ts +37 -0
  259. package/src/commands/low-family/mesh-ledger.ts +62 -0
  260. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  261. package/src/commands/low-family/notification.ts +116 -0
  262. package/src/commands/low-family/refine-config.ts +106 -0
  263. package/src/commands/low-family/session-host.ts +274 -0
  264. package/src/commands/low-family/spec-providerdev.ts +217 -0
  265. package/src/commands/low-family/status-meta.ts +112 -0
  266. package/src/commands/low-family/types.ts +39 -0
  267. package/src/commands/med-family/cli-agent.ts +241 -0
  268. package/src/commands/med-family/fast-forward.ts +230 -0
  269. package/src/commands/med-family/ide.ts +163 -0
  270. package/src/commands/med-family/index.ts +37 -0
  271. package/src/commands/med-family/mesh-crud.ts +1287 -0
  272. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  273. package/src/commands/med-family/mesh-queue.ts +167 -0
  274. package/src/commands/med-family/mesh-restart.ts +92 -0
  275. package/src/commands/med-family/types.ts +153 -0
  276. package/src/commands/mesh-coordinator.ts +334 -124
  277. package/src/commands/router-aggregate-status.ts +209 -0
  278. package/src/commands/router-mesh-session-owner.ts +114 -0
  279. package/src/commands/router-refine.ts +1711 -0
  280. package/src/commands/router-worktree-cleanup.ts +870 -0
  281. package/src/commands/router.ts +795 -4143
  282. package/src/commands/stream-commands.ts +8 -0
  283. package/src/commands/upgrade-helper.ts +310 -45
  284. package/src/config/chat-history.ts +493 -24
  285. package/src/config/config.ts +30 -0
  286. package/src/config/mesh-config.ts +632 -23
  287. package/src/config/mesh-json-config.ts +376 -0
  288. package/src/config/recent-activity.ts +8 -2
  289. package/src/config/registry-resolver.ts +100 -0
  290. package/src/config/repo-settings.ts +111 -0
  291. package/src/daemon/dev-auto-implement.ts +3 -2
  292. package/src/daemon/dev-cli-debug.ts +10 -1
  293. package/src/daemon/dev-server.ts +0 -541
  294. package/src/detection/cli-detector.ts +94 -9
  295. package/src/detection/ide-detector.ts +55 -16
  296. package/src/detection/win32-ide-version.ts +106 -0
  297. package/src/git/change-impact-config.ts +354 -0
  298. package/src/git/git-commands.ts +112 -16
  299. package/src/git/git-diff.ts +81 -11
  300. package/src/git/git-executor.ts +12 -0
  301. package/src/git/git-status.ts +767 -48
  302. package/src/git/git-types.ts +14 -62
  303. package/src/git/git-worktree.ts +261 -4
  304. package/src/git/index.ts +17 -0
  305. package/src/index.ts +207 -13
  306. package/src/installer.d.ts +1 -1
  307. package/src/installer.ts +8 -6
  308. package/src/ipc/local-ipc-server.ts +278 -0
  309. package/src/launch.d.ts +1 -1
  310. package/src/launch.ts +37 -28
  311. package/src/logging/async-batch-writer.ts +55 -0
  312. package/src/logging/command-log.ts +7 -5
  313. package/src/logging/debug-config.ts +25 -0
  314. package/src/logging/debug-trace.ts +7 -2
  315. package/src/logging/log-redactor.ts +100 -0
  316. package/src/logging/log-tail-reader.ts +341 -0
  317. package/src/logging/logger.ts +14 -7
  318. package/src/mesh/contracts.ts +469 -0
  319. package/src/mesh/coordinator-prompt.ts +572 -34
  320. package/src/mesh/coordinator-registry.ts +121 -0
  321. package/src/mesh/mesh-active-work.ts +706 -0
  322. package/src/mesh/mesh-clone-grace.ts +68 -0
  323. package/src/mesh/mesh-completion-synthesis.ts +398 -0
  324. package/src/mesh/mesh-coordinator-config.ts +97 -0
  325. package/src/mesh/mesh-delivery-policy.ts +284 -0
  326. package/src/mesh/mesh-event-classify.ts +78 -0
  327. package/src/mesh/mesh-event-forwarding.ts +1964 -0
  328. package/src/mesh/mesh-event-trace.ts +67 -0
  329. package/src/mesh/mesh-events-coordinator.ts +32 -0
  330. package/src/mesh/mesh-events-pending.ts +1494 -0
  331. package/src/mesh/mesh-events-stale.ts +440 -0
  332. package/src/mesh/mesh-events-utils.ts +443 -0
  333. package/src/mesh/mesh-events.ts +43 -1035
  334. package/src/mesh/mesh-fast-forward.ts +856 -0
  335. package/src/mesh/mesh-host-ownership.ts +111 -0
  336. package/src/mesh/mesh-init.ts +350 -0
  337. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  338. package/src/mesh/mesh-ledger.ts +898 -102
  339. package/src/mesh/mesh-magi-status.ts +223 -0
  340. package/src/mesh/mesh-missions.ts +568 -0
  341. package/src/mesh/mesh-node-identity.ts +2065 -0
  342. package/src/mesh/mesh-queue-assignment.ts +2247 -0
  343. package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
  344. package/src/mesh/mesh-reconcile-config.ts +66 -0
  345. package/src/mesh/mesh-reconcile-identity.ts +103 -0
  346. package/src/mesh/mesh-reconcile-loop.ts +1473 -0
  347. package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
  348. package/src/mesh/mesh-refine-batch.ts +205 -0
  349. package/src/mesh/mesh-refine-gates.ts +1686 -0
  350. package/src/mesh/mesh-refine-status.ts +231 -0
  351. package/src/mesh/mesh-remote-event-pull.ts +279 -0
  352. package/src/mesh/mesh-review-inbox.ts +308 -0
  353. package/src/mesh/mesh-routing.ts +291 -0
  354. package/src/mesh/mesh-runtime-store.ts +2150 -0
  355. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  356. package/src/mesh/mesh-task-inflight.ts +70 -0
  357. package/src/mesh/mesh-task-stats.ts +161 -0
  358. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  359. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  360. package/src/mesh/mesh-work-queue.ts +1437 -147
  361. package/src/mesh/preview-freshness.ts +163 -0
  362. package/src/mesh/refine-config.ts +423 -0
  363. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  364. package/src/providers/acp-provider-instance.ts +43 -10
  365. package/src/providers/approval-utils.d.ts +5 -0
  366. package/src/providers/approval-utils.ts +100 -6
  367. package/src/providers/chat-message-normalization.ts +126 -4
  368. package/src/providers/cli-provider-effect-format.ts +53 -0
  369. package/src/providers/cli-provider-history-dedup.ts +75 -0
  370. package/src/providers/cli-provider-input-prompt.ts +133 -0
  371. package/src/providers/cli-provider-instance-types.ts +131 -0
  372. package/src/providers/cli-provider-instance.ts +2500 -497
  373. package/src/providers/cli-provider-status-helpers.ts +123 -0
  374. package/src/providers/cli-provider-transcript-merge.ts +114 -0
  375. package/src/providers/contracts.d.ts +55 -0
  376. package/src/providers/contracts.ts +160 -6
  377. package/src/providers/extension-provider-instance.ts +12 -7
  378. package/src/providers/external-sources.ts +218 -0
  379. package/src/providers/ide-provider-instance.ts +35 -12
  380. package/src/providers/manual-attendance.ts +105 -0
  381. package/src/providers/native-history/antigravity-claim-registry.ts +131 -0
  382. package/src/providers/native-history/antigravity-cli-transcript.ts +1193 -0
  383. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  384. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  385. package/src/providers/native-history/constants.ts +19 -0
  386. package/src/providers/native-history/dispatcher.ts +503 -0
  387. package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
  388. package/src/providers/native-history/index.ts +30 -0
  389. package/src/providers/provider-instance-manager.ts +71 -0
  390. package/src/providers/provider-instance.ts +24 -1
  391. package/src/providers/provider-loader.ts +700 -55
  392. package/src/providers/provider-schema.ts +87 -14
  393. package/src/providers/provider-trust.ts +114 -0
  394. package/src/providers/read-chat-contract.ts +76 -16
  395. package/src/providers/sdk/README.md +49 -0
  396. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  397. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  398. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  399. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  400. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  401. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  402. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  403. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  404. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  405. package/src/providers/sdk/v1/index.ts +152 -0
  406. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  407. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  408. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  409. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +509 -0
  410. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  411. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  412. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  413. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  414. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  415. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  416. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  417. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  418. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  419. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  420. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  421. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  422. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  423. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  424. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  425. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  426. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  427. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  428. package/src/providers/sdk/v1/validators/index.ts +19 -0
  429. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  430. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  431. package/src/providers/spec/adapter.ts +246 -0
  432. package/src/providers/spec/cli-adapter.ts +1064 -0
  433. package/src/providers/spec/evaluator.ts +407 -0
  434. package/src/providers/spec/fsm-driver.ts +1528 -0
  435. package/src/providers/spec/fsm-evaluator.ts +290 -0
  436. package/src/providers/spec/fsm-loader.ts +128 -0
  437. package/src/providers/spec/fsm-types.ts +301 -0
  438. package/src/providers/spec/native-history-executor.ts +1241 -0
  439. package/src/providers/spec/pre-launch-trust.ts +104 -0
  440. package/src/providers/spec/route.ts +51 -0
  441. package/src/providers/spec/types.ts +284 -0
  442. package/src/providers/status-monitor.d.ts +7 -7
  443. package/src/providers/status-monitor.ts +37 -22
  444. package/src/providers/transcript-v2.ts +567 -0
  445. package/src/providers/types/interactive-prompt.ts +536 -0
  446. package/src/providers/version-archive.ts +64 -24
  447. package/src/providers/working-dir.ts +23 -0
  448. package/src/repo-mesh-types.ts +868 -13
  449. package/src/runtime-defaults.ts +39 -0
  450. package/src/session-host/managed-host.ts +218 -0
  451. package/src/session-host/runtime-surface.ts +20 -80
  452. package/src/sessions/registry.ts +6 -0
  453. package/src/shared-types-extra.ts +2 -4
  454. package/src/shared-types.d.ts +8 -0
  455. package/src/shared-types.ts +124 -55
  456. package/src/status/builders.ts +26 -6
  457. package/src/status/normalize.ts +2 -0
  458. package/src/status/reporter.ts +19 -1
  459. package/src/status/snapshot.ts +95 -26
  460. package/src/system/hash.ts +23 -0
  461. package/src/system/host-memory.ts +29 -12
  462. package/src/system/load-better-sqlite3.ts +68 -0
  463. package/src/types.ts +5 -0
  464. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  465. package/dist/mesh/mesh-sync.d.ts +0 -53
  466. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  467. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  468. package/src/mesh/mesh-sync.ts +0 -111
@@ -58,6 +58,40 @@ const savedHistoryFileSummaryCache = new Map<string, SavedHistoryFileSummaryCach
58
58
  const savedHistoryBackgroundRefresh = new Set<string>();
59
59
  const savedHistoryRollupInFlight = new Set<string>();
60
60
 
61
+ // Bounded-tail read cache. The dashboard re-subscribes and polls hot sessions
62
+ // every ~2.5s; without a cache each poll re-reads/parses/sorts the whole
63
+ // conversation just to slice a small tail. We key on (type, sessionId,
64
+ // pagination args) plus the on-disk size+mtime signature so an UNCHANGED
65
+ // session returns the previously computed tail in O(1) and only re-reads when a
66
+ // new message is appended (signature changes). The map is bounded by a small
67
+ // LRU to keep memory flat regardless of how many sessions are touched.
68
+ interface BoundedTailCacheEntry {
69
+ signature: string;
70
+ result: { messages: HistoryMessage[]; hasMore: boolean };
71
+ }
72
+
73
+ const BOUNDED_TAIL_CACHE_MAX_ENTRIES = 64;
74
+ const boundedTailReadCache = new Map<string, BoundedTailCacheEntry>();
75
+
76
+ function readBoundedTailCache(key: string, signature: string): { messages: HistoryMessage[]; hasMore: boolean } | null {
77
+ const cached = boundedTailReadCache.get(key);
78
+ if (!cached || cached.signature !== signature) return null;
79
+ // Refresh LRU recency.
80
+ boundedTailReadCache.delete(key);
81
+ boundedTailReadCache.set(key, cached);
82
+ return cached.result;
83
+ }
84
+
85
+ function writeBoundedTailCache(key: string, signature: string, result: { messages: HistoryMessage[]; hasMore: boolean }): void {
86
+ boundedTailReadCache.delete(key);
87
+ boundedTailReadCache.set(key, { signature, result });
88
+ while (boundedTailReadCache.size > BOUNDED_TAIL_CACHE_MAX_ENTRIES) {
89
+ const oldest = boundedTailReadCache.keys().next().value;
90
+ if (oldest === undefined) break;
91
+ boundedTailReadCache.delete(oldest);
92
+ }
93
+ }
94
+
61
95
  interface HistoryMessage {
62
96
  ts: string; // ISO timestamp
63
97
  receivedAt: number; // epoch ms
@@ -138,6 +172,15 @@ function collapseReplayAssistantTurns(messages: HistoryMessage[], historyBehavio
138
172
  }
139
173
 
140
174
  if (message.role === 'assistant') {
175
+ // Tool / activity bubbles are distinct events, not replayed prose —
176
+ // collapsing them would erase every tool call and result after the
177
+ // turn's first assistant message. Only consecutive *prose* assistant
178
+ // turns are the replay-dedup target this collapse exists for.
179
+ const isActivity = message.kind === 'tool' || message.kind === 'terminal' || message.kind === 'thought';
180
+ if (isActivity) {
181
+ collapsed.push(message);
182
+ continue;
183
+ }
141
184
  if (sawAssistantSinceLastUser) continue;
142
185
  sawAssistantSinceLastUser = true;
143
186
  collapsed.push(message);
@@ -1180,6 +1223,324 @@ function pageHistoryRecords(
1180
1223
  return { messages: sliced, hasMore: startInclusive > 0 };
1181
1224
  }
1182
1225
 
1226
+ // A finite tail request can be served by reading only the newest files instead
1227
+ // of the whole conversation. Treat very large limits (e.g. MAX_SAFE_INTEGER, or
1228
+ // anything past a generous ceiling) as a full-history request so restore/seed
1229
+ // callers keep their existing behavior.
1230
+ const BOUNDED_TAIL_MAX_LIMIT = 5_000;
1231
+ // Slack added to the requested window before sorting/dedup/collapse so the
1232
+ // boundary message at the top of the tail dedupes/collapses identically to a
1233
+ // full read. Modest and bounded — it only widens the parse window, not output.
1234
+ const BOUNDED_TAIL_SLACK = 50;
1235
+
1236
+ function isBoundedTailRequest(limit: number, offset: number, excludeRecentCount: number): boolean {
1237
+ const numericLimit = Number(limit);
1238
+ if (!Number.isFinite(numericLimit) || numericLimit <= 0) return false;
1239
+ if (numericLimit > BOUNDED_TAIL_MAX_LIMIT) return false;
1240
+ const numericOffset = Number(offset);
1241
+ const numericExclude = Number(excludeRecentCount);
1242
+ if (!Number.isFinite(numericOffset) || !Number.isFinite(numericExclude)) return false;
1243
+ return true;
1244
+ }
1245
+
1246
+ // Byte threshold below which a file is small enough that reading the whole
1247
+ // thing is cheaper than seeking. Reverse-seek pays off only on large files.
1248
+ const REVERSE_TAIL_SMALL_FILE_BYTES = 64 * 1024;
1249
+ // Chunk size for backward reads. We read the file tail one chunk at a time
1250
+ // (newest bytes first) until we have collected enough complete lines.
1251
+ const REVERSE_TAIL_CHUNK_BYTES = 64 * 1024;
1252
+
1253
+ // Per-(file path) incremental tail cache. A hot session's daily JSONL file grows
1254
+ // append-only while it generates; the size+mtime signature on the bounded-tail
1255
+ // read cache therefore invalidates on every append and forces a full re-read.
1256
+ // Here we keep the most recently decoded tail LINES for a file plus the byte
1257
+ // length we read them from. When the file has only grown (append-only: size
1258
+ // increased, the previously-read prefix is unchanged) we read just the new bytes
1259
+ // from `size` onward and splice them onto the retained tail — no full re-parse.
1260
+ // Truncation/rotation (size shrank, or a fresh inode) drops the entry and falls
1261
+ // back to a full reverse-seek.
1262
+ interface IncrementalTailCacheEntry {
1263
+ // File length (bytes) we have already consumed into `lines`.
1264
+ size: number;
1265
+ mtimeMs: number;
1266
+ // Decoded complete lines (oldest-first) covering at least the tail window.
1267
+ // Bounded to TAIL_LINES_RETAINED so memory stays flat for huge files.
1268
+ lines: string[];
1269
+ // True when `lines` is the entire file (head reached), so older pages can
1270
+ // trust that nothing precedes the retained window.
1271
+ coversWholeFile: boolean;
1272
+ }
1273
+
1274
+ // How many trailing lines we retain per file. The bounded-tail caller never
1275
+ // asks for more than BOUNDED_TAIL_MAX_LIMIT + slack; keep a generous multiple so
1276
+ // repeated reads at the same window are served incrementally.
1277
+ const TAIL_LINES_RETAINED = BOUNDED_TAIL_MAX_LIMIT + 2 * BOUNDED_TAIL_SLACK;
1278
+ const INCREMENTAL_TAIL_CACHE_MAX_ENTRIES = 64;
1279
+ const incrementalTailCache = new Map<string, IncrementalTailCacheEntry>();
1280
+
1281
+ function evictIncrementalTailCache(): void {
1282
+ while (incrementalTailCache.size > INCREMENTAL_TAIL_CACHE_MAX_ENTRIES) {
1283
+ const oldest = incrementalTailCache.keys().next().value;
1284
+ if (oldest === undefined) break;
1285
+ incrementalTailCache.delete(oldest);
1286
+ }
1287
+ }
1288
+
1289
+ // Split a Buffer into complete lines plus a leftover head fragment, partitioning
1290
+ // only on the newline byte (0x0A). 0x0A never appears inside a multibyte UTF-8
1291
+ // sequence, so decoding each complete byte segment is boundary-safe. The leftover
1292
+ // (bytes before the first newline) is returned undecoded so a caller stitching
1293
+ // chunks together never splits a multibyte char.
1294
+ function splitBufferLines(buf: Buffer): { head: Buffer; lines: string[] } {
1295
+ const lines: string[] = [];
1296
+ let lineEnd = buf.length;
1297
+ let firstNewline = -1;
1298
+ for (let i = buf.length - 1; i >= 0; i--) {
1299
+ if (buf[i] !== 0x0a) continue;
1300
+ if (i + 1 < lineEnd) {
1301
+ lines.push(buf.toString('utf-8', i + 1, lineEnd));
1302
+ }
1303
+ lineEnd = i;
1304
+ firstNewline = i;
1305
+ }
1306
+ // Lines were collected newest-first; restore oldest-first for the segment
1307
+ // that follows the first (lowest-index) newline.
1308
+ lines.reverse();
1309
+ const head = firstNewline >= 0 ? buf.subarray(0, firstNewline) : buf;
1310
+ return { head, lines };
1311
+ }
1312
+
1313
+ // Read the last bytes of a file, newest-first, until we have at least `needed`
1314
+ // complete lines (or reach the start of the file). Returns lines oldest-first and
1315
+ // whether the whole file was consumed. Boundary-safe: lines are cut on the
1316
+ // newline byte only, so multibyte UTF-8 chars are never split, and a trailing
1317
+ // partial line (no terminating newline) is preserved as a complete final line.
1318
+ function readReverseTailLines(filePath: string, needed: number): { lines: string[]; coversWholeFile: boolean; size: number; mtimeMs: number } {
1319
+ const fd = fs.openSync(filePath, 'r');
1320
+ try {
1321
+ const stat = fs.fstatSync(fd);
1322
+ const size = stat.size;
1323
+ let position = size;
1324
+ // `carry` holds bytes belonging to a line that straddles the current
1325
+ // chunk boundary (its start is in an older, not-yet-read chunk).
1326
+ let carry: Buffer = Buffer.alloc(0);
1327
+ const collected: string[] = [];
1328
+
1329
+ while (position > 0 && collected.length < needed) {
1330
+ const chunkSize = Math.min(REVERSE_TAIL_CHUNK_BYTES, position);
1331
+ position -= chunkSize;
1332
+ const chunk = Buffer.alloc(chunkSize);
1333
+ fs.readSync(fd, chunk, 0, chunkSize, position);
1334
+ const combined = carry.length ? Buffer.concat([chunk, carry]) : chunk;
1335
+ const { head, lines } = splitBufferLines(combined);
1336
+ // `head` is the (possibly partial) line whose start lies further back;
1337
+ // hold it for the next (older) chunk to complete.
1338
+ carry = head;
1339
+ // `lines` are oldest-first within this combined buffer; prepend them
1340
+ // ahead of what we already collected (which is strictly newer).
1341
+ for (let i = lines.length - 1; i >= 0; i--) {
1342
+ collected.push(lines[i]);
1343
+ }
1344
+ }
1345
+
1346
+ const reachedStart = position <= 0;
1347
+ if (reachedStart && carry.length) {
1348
+ // Leftover head at the start of the file is itself a complete line.
1349
+ collected.push(carry.toString('utf-8'));
1350
+ }
1351
+ // `collected` is newest-first; restore oldest-first.
1352
+ collected.reverse();
1353
+ return { lines: collected, coversWholeFile: reachedStart, size, mtimeMs: stat.mtimeMs };
1354
+ } finally {
1355
+ fs.closeSync(fd);
1356
+ }
1357
+ }
1358
+
1359
+ // Return the tail lines (oldest-first) for a single history file, reading as
1360
+ // little of the file as possible. Strategy:
1361
+ // - Small files: one readFileSync (seeking is not worth the syscalls).
1362
+ // - Large files: reverse byte-seek for the newest `needed` lines.
1363
+ // - Append-only growth since the last read: read only the appended bytes and
1364
+ // splice them onto the retained tail (no full re-parse) — this is what keeps
1365
+ // a hot, still-generating session cheap to poll.
1366
+ // `needed` is a soft floor; we may return more (whole small files / retained
1367
+ // window). Lines include any trailing partial (unterminated) final line.
1368
+ function readFileTailLines(filePath: string, needed: number): { lines: string[]; coversWholeFile: boolean } {
1369
+ let stat: fs.Stats;
1370
+ try {
1371
+ stat = fs.statSync(filePath);
1372
+ } catch {
1373
+ return { lines: [], coversWholeFile: true };
1374
+ }
1375
+ const size = stat.size;
1376
+ const mtimeMs = stat.mtimeMs;
1377
+ if (size === 0) {
1378
+ incrementalTailCache.delete(filePath);
1379
+ return { lines: [], coversWholeFile: true };
1380
+ }
1381
+
1382
+ const cached = incrementalTailCache.get(filePath);
1383
+ if (cached) {
1384
+ if (cached.size === size && cached.mtimeMs === mtimeMs) {
1385
+ // Unchanged since last read — reuse retained tail. Refresh LRU.
1386
+ incrementalTailCache.delete(filePath);
1387
+ incrementalTailCache.set(filePath, cached);
1388
+ if (cached.coversWholeFile || cached.lines.length >= needed) {
1389
+ return { lines: cached.lines, coversWholeFile: cached.coversWholeFile };
1390
+ }
1391
+ // Retained window is smaller than this request needs; fall through
1392
+ // to a fresh reverse-seek for the larger window.
1393
+ } else if (size > cached.size) {
1394
+ // Append-only growth: the prefix [0, cached.size) is assumed
1395
+ // unchanged (JSONL is append-only). Read just the new bytes and
1396
+ // stitch them — but verify the byte at cached.size-1 is still the
1397
+ // newline that terminated our last retained line, so a rewrite that
1398
+ // happens to grow the file (compaction) is detected and rejected.
1399
+ const incremental = tryIncrementalTailGrowth(filePath, cached, size, mtimeMs, needed);
1400
+ if (incremental) return { lines: incremental.lines, coversWholeFile: incremental.coversWholeFile };
1401
+ }
1402
+ // size shrank (truncation/rotation) or incremental failed → drop & reload.
1403
+ incrementalTailCache.delete(filePath);
1404
+ }
1405
+
1406
+ if (size <= REVERSE_TAIL_SMALL_FILE_BYTES) {
1407
+ let content: string;
1408
+ try {
1409
+ content = fs.readFileSync(filePath, 'utf-8');
1410
+ } catch {
1411
+ return { lines: [], coversWholeFile: true };
1412
+ }
1413
+ const lines = content.split('\n');
1414
+ // A trailing newline yields a final empty element; drop only that one so
1415
+ // an unterminated partial last line is still preserved.
1416
+ if (lines.length && lines[lines.length - 1] === '') lines.pop();
1417
+ storeIncrementalTailCache(filePath, size, mtimeMs, lines, true);
1418
+ return { lines, coversWholeFile: true };
1419
+ }
1420
+
1421
+ let result: { lines: string[]; coversWholeFile: boolean; size: number; mtimeMs: number };
1422
+ try {
1423
+ result = readReverseTailLines(filePath, needed);
1424
+ } catch {
1425
+ return { lines: [], coversWholeFile: true };
1426
+ }
1427
+ storeIncrementalTailCache(filePath, result.size, result.mtimeMs, result.lines, result.coversWholeFile);
1428
+ return { lines: result.lines, coversWholeFile: result.coversWholeFile };
1429
+ }
1430
+
1431
+ // Read appended bytes [cached.size, size) and splice them onto the retained tail.
1432
+ // Returns null if the prior byte is not a newline (the retained tail did not end
1433
+ // on a record boundary, e.g. the file was rewritten) so the caller can full-reload.
1434
+ function tryIncrementalTailGrowth(
1435
+ filePath: string,
1436
+ cached: IncrementalTailCacheEntry,
1437
+ size: number,
1438
+ mtimeMs: number,
1439
+ needed: number,
1440
+ ): { lines: string[]; coversWholeFile: boolean } | null {
1441
+ const fd = fs.openSync(filePath, 'r');
1442
+ try {
1443
+ // Confirm the byte ending the previously-read prefix is still a newline.
1444
+ if (cached.size > 0) {
1445
+ const boundary = Buffer.alloc(1);
1446
+ fs.readSync(fd, boundary, 0, 1, cached.size - 1);
1447
+ if (boundary[0] !== 0x0a) return null;
1448
+ }
1449
+ const appendedLength = size - cached.size;
1450
+ const appended = Buffer.alloc(appendedLength);
1451
+ fs.readSync(fd, appended, 0, appendedLength, cached.size);
1452
+ const newLines = appended.toString('utf-8').split('\n');
1453
+ if (newLines.length && newLines[newLines.length - 1] === '') newLines.pop();
1454
+ const merged = cached.lines.concat(newLines);
1455
+ // Keep memory flat: retain only the trailing window.
1456
+ const trimmed = merged.length > TAIL_LINES_RETAINED
1457
+ ? merged.slice(merged.length - TAIL_LINES_RETAINED)
1458
+ : merged;
1459
+ const coversWholeFile = cached.coversWholeFile && trimmed.length === merged.length;
1460
+ storeIncrementalTailCache(filePath, size, mtimeMs, trimmed, coversWholeFile);
1461
+ if (coversWholeFile || trimmed.length >= needed) {
1462
+ return { lines: trimmed, coversWholeFile };
1463
+ }
1464
+ // Should not happen (we only grew), but be safe.
1465
+ return { lines: trimmed, coversWholeFile };
1466
+ } catch {
1467
+ return null;
1468
+ } finally {
1469
+ fs.closeSync(fd);
1470
+ }
1471
+ }
1472
+
1473
+ function storeIncrementalTailCache(filePath: string, size: number, mtimeMs: number, lines: string[], coversWholeFile: boolean): void {
1474
+ const retained = lines.length > TAIL_LINES_RETAINED ? lines.slice(lines.length - TAIL_LINES_RETAINED) : lines;
1475
+ const covers = coversWholeFile && retained.length === lines.length;
1476
+ incrementalTailCache.delete(filePath);
1477
+ incrementalTailCache.set(filePath, { size, mtimeMs, lines: retained, coversWholeFile: covers });
1478
+ evictIncrementalTailCache();
1479
+ }
1480
+
1481
+ // Read newest-first only as many files as needed to cover the requested window
1482
+ // plus slack. listHistoryFiles already returns files reversed (newest-first), so
1483
+ // we accumulate (de-duped) candidates from the end and stop once we have enough,
1484
+ // then hand the bounded window to pageHistoryRecords in chronological order.
1485
+ function readBoundedTailRecords(
1486
+ agentType: string,
1487
+ dir: string,
1488
+ files: string[],
1489
+ needed: number,
1490
+ ): { records: HistoryMessage[]; readAllFiles: boolean } {
1491
+ const collected: HistoryMessage[] = [];
1492
+ const seen = new Set<string>();
1493
+ let readAllFiles = true;
1494
+
1495
+ for (let f = 0; f < files.length; f++) {
1496
+ const filePath = path.join(dir, files[f]);
1497
+ // Read only the file tail needed to top up the window — for a large
1498
+ // single-day file this seeks the last `needed` lines instead of parsing
1499
+ // the whole file. We re-derive the per-file floor each iteration from how
1500
+ // many records are still missing (plus slack so dedup at the boundary is
1501
+ // stable), capped at `needed`.
1502
+ const remaining = Math.max(0, needed - collected.length);
1503
+ const perFileNeeded = Math.min(needed, remaining + BOUNDED_TAIL_SLACK);
1504
+ const { lines, coversWholeFile } = readFileTailLines(filePath, perFileNeeded);
1505
+ // Walk this file's tail lines newest-first so we fill the tail window from
1506
+ // the bottom. seen-dedup keeps the same first-wins-by-newest semantics the
1507
+ // full read produced (files are processed newest-first there too).
1508
+ for (let i = lines.length - 1; i >= 0; i--) {
1509
+ const line = lines[i];
1510
+ if (!line) continue;
1511
+ try {
1512
+ const parsed = JSON.parse(line) as HistoryMessage;
1513
+ const sanitizedMessage = sanitizeHistoryMessage(agentType, parsed);
1514
+ if (!sanitizedMessage) continue;
1515
+ const hash = buildHistoryMessageHash(agentType, sanitizedMessage);
1516
+ if (seen.has(hash)) continue;
1517
+ seen.add(hash);
1518
+ collected.push(sanitizedMessage);
1519
+ } catch { /* skip invalid lines */ }
1520
+ }
1521
+ // If we only read this file's tail (its head was not reached), older
1522
+ // messages remain within this very file — the conversation is NOT fully
1523
+ // represented even if this is the last file, so hasMore must stay true.
1524
+ if (!coversWholeFile) {
1525
+ readAllFiles = false;
1526
+ break;
1527
+ }
1528
+ // Stop once we have the window AND there is at least one more file (so a
1529
+ // potential older boundary message exists). If this is the last file we
1530
+ // fall through and mark the whole history as read.
1531
+ if (collected.length >= needed && f < files.length - 1) {
1532
+ readAllFiles = false;
1533
+ break;
1534
+ }
1535
+ }
1536
+
1537
+ // collected is newest-first across the bounded window; restore chronological
1538
+ // (oldest-first) order before paging. pageHistoryRecords re-sorts by
1539
+ // receivedAt regardless, so this is purely for stable input ordering.
1540
+ collected.reverse();
1541
+ return { records: collected, readAllFiles };
1542
+ }
1543
+
1183
1544
  export function readChatHistory(
1184
1545
  agentType: string,
1185
1546
  offset: number = 0,
@@ -1196,6 +1557,33 @@ export function readChatHistory(
1196
1557
  // JSONL file list — filter by persistent history key when specified
1197
1558
  const files = listHistoryFiles(dir, historySessionId);
1198
1559
 
1560
+ const bounded = isBoundedTailRequest(limit, offset, excludeRecentCount);
1561
+
1562
+ if (bounded) {
1563
+ const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
1564
+ const cacheKey = `${sanitized}\0${historySessionId || ''}\0${offset}\0${limit}\0${excludeRecentCount}\0${historyBehavior?.collapseConsecutiveAssistantTurns ? '1' : '0'}`;
1565
+ const signature = buildSavedHistoryCacheSignature(files, fileSignatures);
1566
+ const cached = readBoundedTailCache(cacheKey, signature);
1567
+ if (cached) return cached;
1568
+
1569
+ // Window large enough that the top boundary dedupes/collapses the same
1570
+ // as a full read. hasMore reflects whether older messages exist beyond
1571
+ // the window we actually read.
1572
+ const numericLimit = Math.max(1, Number(limit));
1573
+ const numericOffset = Math.max(0, Number(offset));
1574
+ const numericExclude = Math.max(0, Number(excludeRecentCount));
1575
+ const needed = numericLimit + numericOffset + numericExclude + Math.max(BOUNDED_TAIL_SLACK, numericLimit);
1576
+ const { records, readAllFiles } = readBoundedTailRecords(agentType, dir, files, needed);
1577
+ const result = pageHistoryRecords(agentType, records, offset, limit, excludeRecentCount, historyBehavior);
1578
+ // If we read every file, the conversation is fully represented in the
1579
+ // window and pageHistoryRecords' hasMore is authoritative. If we
1580
+ // stopped early there are older messages we never read, so hasMore
1581
+ // must stay true regardless of the in-window slice position.
1582
+ const boundedResult = readAllFiles ? result : { messages: result.messages, hasMore: true };
1583
+ writeBoundedTailCache(cacheKey, signature, boundedResult);
1584
+ return boundedResult;
1585
+ }
1586
+
1199
1587
  const allMessages: HistoryMessage[] = [];
1200
1588
  const seen = new Set<string>();
1201
1589
 
@@ -1345,7 +1733,16 @@ function rewriteCanonicalSavedHistory(agentType: string, historySessionId: strin
1345
1733
 
1346
1734
  export type ProviderNativeHistoryScripts = Record<string, ((input: any) => any) | undefined>;
1347
1735
 
1348
- type ProviderNativeHistoryReadResult = { records: HistoryMessage[]; sourcePath: string; sourceMtimeMs: number };
1736
+ type ProviderNativeHistoryReadResult = {
1737
+ records: HistoryMessage[];
1738
+ sourcePath: string;
1739
+ sourceMtimeMs: number;
1740
+ providerSessionId?: string;
1741
+ workspace?: string;
1742
+ nativeHistoryCoverage?: string;
1743
+ partialReason?: string;
1744
+ unavailableReason?: string;
1745
+ };
1349
1746
 
1350
1747
  function getNativeHistoryScriptName(canonicalHistory: ProviderCanonicalHistoryConfig | undefined, key: 'readSession' | 'listSessions'): string {
1351
1748
  const configured = canonicalHistory?.scripts?.[key];
@@ -1367,19 +1764,42 @@ function normalizeProviderNativeHistoryRecords(agentType: string, historySession
1367
1764
  if (!Array.isArray(records)) return [];
1368
1765
  const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
1369
1766
  return records
1370
- .map((record: any) => sanitizeHistoryMessage(agentType, {
1371
- ts: typeof record?.ts === 'string' ? record.ts : new Date(Number(record?.receivedAt) || Date.now()).toISOString(),
1372
- receivedAt: Number(record?.receivedAt) || Date.parse(record?.ts || '') || Date.now(),
1373
- role: record?.role,
1374
- content: String(record?.content || ''),
1375
- kind: record?.kind || (record?.role === 'system' ? 'session_start' : 'standard'),
1376
- senderName: record?.senderName,
1377
- agent: agentType,
1378
- instanceId: record?.instanceId,
1379
- historySessionId: normalizeSavedHistorySessionId(record?.historySessionId || normalizedSessionId),
1380
- sessionTitle: record?.sessionTitle,
1381
- workspace: record?.workspace,
1382
- } as HistoryMessage))
1767
+ .map((record: any) => {
1768
+ const base: HistoryMessage = {
1769
+ ts: typeof record?.ts === 'string' ? record.ts : new Date(Number(record?.receivedAt) || Date.now()).toISOString(),
1770
+ receivedAt: Number(record?.receivedAt) || Date.parse(record?.ts || '') || Date.now(),
1771
+ role: record?.role,
1772
+ content: String(record?.content || ''),
1773
+ kind: record?.kind || (record?.role === 'system' ? 'session_start' : 'standard'),
1774
+ senderName: record?.senderName,
1775
+ agent: agentType,
1776
+ instanceId: record?.instanceId,
1777
+ historySessionId: normalizeSavedHistorySessionId(record?.historySessionId || normalizedSessionId),
1778
+ sessionTitle: record?.sessionTitle,
1779
+ workspace: record?.workspace,
1780
+ } as HistoryMessage;
1781
+ // (A2.3 v2 identity passthrough) — if the producer (native_history.js)
1782
+ // emitted v2 stable identity, keep it across the sanitize layer so
1783
+ // downstream (chat-commands.ts normalizeNativeHistoryMessages) sees
1784
+ // the producer's contract output instead of recomputing from index
1785
+ // and content hash. v1 producers without these fields are unaffected.
1786
+ if (typeof record?.providerUnitKey === 'string' && record.providerUnitKey) {
1787
+ (base as any).providerUnitKey = record.providerUnitKey;
1788
+ }
1789
+ if (typeof record?.bubbleId === 'string' && record.bubbleId) {
1790
+ (base as any).bubbleId = record.bubbleId;
1791
+ }
1792
+ if (typeof record?.sequence === 'number' && Number.isFinite(record.sequence)) {
1793
+ (base as any).sequence = record.sequence;
1794
+ }
1795
+ if (typeof record?._turnKey === 'string' && record._turnKey) {
1796
+ (base as any)._turnKey = record._turnKey;
1797
+ }
1798
+ if (typeof record?.bubbleState === 'string' && record.bubbleState) {
1799
+ (base as any).bubbleState = record.bubbleState;
1800
+ }
1801
+ return sanitizeHistoryMessage(agentType, base);
1802
+ })
1383
1803
  .filter(Boolean) as HistoryMessage[];
1384
1804
  }
1385
1805
 
@@ -1387,27 +1807,51 @@ function callProviderNativeHistoryRead(
1387
1807
  agentType: string,
1388
1808
  canonicalHistory: ProviderCanonicalHistoryConfig | undefined,
1389
1809
  scripts: ProviderNativeHistoryScripts | undefined,
1390
- historySessionId: string,
1810
+ historySessionId: string | undefined,
1391
1811
  workspace?: string,
1812
+ excludeInProgressTurn?: boolean,
1813
+ sessionStartedAtMs?: number,
1814
+ envOverrides?: Record<string, string>,
1815
+ forceRefresh?: boolean,
1392
1816
  ): ProviderNativeHistoryReadResult | null {
1393
1817
  const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, 'readSession');
1394
1818
  if (!fn) return null;
1819
+ const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || '');
1395
1820
  const result = fn({
1396
1821
  agentType,
1397
- sessionId: historySessionId,
1398
- historySessionId,
1822
+ sessionId: normalizedSessionId,
1823
+ // Arm the native-history executor's session pin guard. When the
1824
+ // instance is already bound to a provider session, pass that id as
1825
+ // `providerSessionId` so the executor rejects any *other* newest
1826
+ // session it would otherwise pick (hermes ≥0.14 creates a fresh
1827
+ // `sessions` row per internal sub-session, so an unpinned
1828
+ // newest-wins query drifts to a different id on every read →
1829
+ // re-bind churn + unbounded history re-hydration). When there is no
1830
+ // bound id yet (first-bind / workspace-only discovery) this is '',
1831
+ // which leaves the guard disarmed so discovery still works.
1832
+ providerSessionId: normalizedSessionId,
1833
+ historySessionId: normalizedSessionId,
1399
1834
  workspace,
1400
1835
  format: canonicalHistory?.format,
1401
1836
  watchPath: canonicalHistory?.watchPath,
1402
- args: { sessionId: historySessionId, historySessionId, workspace },
1837
+ excludeInProgressTurn: excludeInProgressTurn === true,
1838
+ sessionStartedAtMs,
1839
+ envOverrides,
1840
+ forceRefresh: forceRefresh === true,
1841
+ args: { sessionId: normalizedSessionId, historySessionId: normalizedSessionId, workspace, excludeInProgressTurn: excludeInProgressTurn === true, sessionStartedAtMs, envOverrides, forceRefresh: forceRefresh === true },
1403
1842
  });
1404
1843
  if (!result || typeof result !== 'object') return null;
1405
- const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, (result as any).messages || (result as any).records);
1844
+ const records = normalizeProviderNativeHistoryRecords(agentType, normalizedSessionId, (result as any).messages || (result as any).records);
1406
1845
  if (records.length === 0) return null;
1407
1846
  return {
1408
1847
  records,
1409
1848
  sourcePath: typeof (result as any).sourcePath === 'string' ? (result as any).sourcePath : '',
1410
1849
  sourceMtimeMs: Number((result as any).sourceMtimeMs) || 0,
1850
+ providerSessionId: typeof (result as any).providerSessionId === 'string' ? (result as any).providerSessionId.trim() : undefined,
1851
+ workspace: typeof (result as any).workspace === 'string' ? (result as any).workspace.trim() : undefined,
1852
+ nativeHistoryCoverage: typeof (result as any).nativeHistoryCoverage === 'string' ? (result as any).nativeHistoryCoverage.trim() : undefined,
1853
+ partialReason: typeof (result as any).partialReason === 'string' ? (result as any).partialReason.trim() : undefined,
1854
+ unavailableReason: typeof (result as any).unavailableReason === 'string' ? (result as any).unavailableReason.trim() : undefined,
1411
1855
  };
1412
1856
  }
1413
1857
 
@@ -1417,10 +1861,15 @@ function buildNativeHistoryReadResult(
1417
1861
  scripts: ProviderNativeHistoryScripts | undefined,
1418
1862
  historySessionId: string | undefined,
1419
1863
  workspace?: string,
1864
+ excludeInProgressTurn?: boolean,
1865
+ sessionStartedAtMs?: number,
1866
+ envOverrides?: Record<string, string>,
1867
+ forceRefresh?: boolean,
1420
1868
  ): ProviderNativeHistoryReadResult | null {
1421
1869
  const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || '');
1422
- if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
1423
- return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
1870
+ const normalizedWorkspace = typeof workspace === 'string' ? workspace.trim() : '';
1871
+ if (!canonicalHistory || (!normalizedSessionId && !normalizedWorkspace) || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
1872
+ return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace, excludeInProgressTurn, sessionStartedAtMs, envOverrides, forceRefresh);
1424
1873
  }
1425
1874
 
1426
1875
  function materializeNativeHistoryToMirror(
@@ -1476,16 +1925,36 @@ export function readProviderChatHistory(
1476
1925
  excludeRecentCount?: number;
1477
1926
  historyBehavior?: ProviderHistoryBehavior;
1478
1927
  scripts?: ProviderNativeHistoryScripts;
1928
+ excludeInProgressTurn?: boolean;
1929
+ sessionStartedAtMs?: number;
1930
+ envOverrides?: Record<string, string>;
1931
+ forceRefresh?: boolean;
1479
1932
  } = {},
1480
- ): { messages: HistoryMessage[]; hasMore: boolean; source: 'provider-native' | 'adhdev-mirror' | 'native-unavailable'; sourcePath?: string; sourceMtimeMs?: number } {
1481
- if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
1482
- const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
1933
+ ): {
1934
+ messages: HistoryMessage[];
1935
+ hasMore: boolean;
1936
+ source: 'provider-native' | 'adhdev-mirror' | 'native-unavailable';
1937
+ sourcePath?: string;
1938
+ sourceMtimeMs?: number;
1939
+ providerSessionId?: string;
1940
+ workspace?: string;
1941
+ nativeHistoryCoverage?: string;
1942
+ partialReason?: string;
1943
+ unavailableReason?: string;
1944
+ } {
1945
+ if (isNativeSourceCanonicalHistory(options.canonicalHistory) && (options.historySessionId || options.workspace)) {
1946
+ const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace, options.excludeInProgressTurn, options.sessionStartedAtMs, options.envOverrides, options.forceRefresh);
1483
1947
  if (!nativeResult) return { messages: [], hasMore: false, source: 'native-unavailable' };
1484
1948
  return {
1485
1949
  ...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
1486
1950
  source: 'provider-native',
1487
1951
  sourcePath: nativeResult.sourcePath,
1488
1952
  sourceMtimeMs: nativeResult.sourceMtimeMs,
1953
+ providerSessionId: nativeResult.providerSessionId,
1954
+ workspace: nativeResult.workspace,
1955
+ nativeHistoryCoverage: nativeResult.nativeHistoryCoverage,
1956
+ partialReason: nativeResult.partialReason,
1957
+ unavailableReason: nativeResult.unavailableReason,
1489
1958
  };
1490
1959
  }
1491
1960
  return {
@@ -123,6 +123,22 @@ export interface ADHDevConfig {
123
123
  // Optional explicit provider override root (for example a local adhdev-providers checkout)
124
124
  providerDir?: string;
125
125
 
126
+ /**
127
+ * Optional provider registry base URL override (for example a self-hosted
128
+ * registry). Highest-priority source in the registry resolver, ahead of the
129
+ * `ADHDEV_REGISTRY_URL` env var and the vendor default. See
130
+ * `config/registry-resolver.ts`.
131
+ */
132
+ registryUrl?: string;
133
+
134
+ /**
135
+ * Optional provider tarball (archive) URL override so self-hosters can point
136
+ * the daemon at their own provider mirror instead of the vendor GitHub repo.
137
+ * Highest-priority source, ahead of `ADHDEV_PROVIDER_TARBALL_URL` and the
138
+ * vendor default. See `config/registry-resolver.ts`.
139
+ */
140
+ providerTarballUrl?: string;
141
+
126
142
  /** Preferred daemon update channel. Defaults to stable/latest. */
127
143
  updateChannel?: ReleaseChannel;
128
144
 
@@ -233,6 +249,8 @@ function normalizeConfig(raw: unknown): ADHDevConfig & { activeWorkspaceId?: str
233
249
  ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
234
250
  providerSourceMode: resolveProviderSourceMode(parsed.providerSourceMode, parsed.disableUpstream),
235
251
  providerDir: asOptionalString(parsed.providerDir),
252
+ registryUrl: asOptionalString(parsed.registryUrl),
253
+ providerTarballUrl: asOptionalString(parsed.providerTarballUrl),
236
254
  updateChannel: parsed.updateChannel === 'preview' ? 'preview' : 'stable',
237
255
  terminalSizingMode: parsed.terminalSizingMode === 'fit' ? 'fit' : 'measured',
238
256
  };
@@ -272,6 +290,18 @@ export function getConfigDir(): string {
272
290
  return dir;
273
291
  }
274
292
 
293
+ /**
294
+ * Get the daemon runtime data directory (~/.adhdev/daemon/).
295
+ * Distinct from the user-config dir so runtime state can be cleared independently.
296
+ */
297
+ export function getDaemonDataDir(): string {
298
+ const dir = join(getConfigDir(), 'daemon');
299
+ if (!existsSync(dir)) {
300
+ mkdirSync(dir, { recursive: true });
301
+ }
302
+ return dir;
303
+ }
304
+
275
305
  /**
276
306
  * Get the config file path
277
307
  */