@adhdev/daemon-core 0.9.82-rc.49 → 0.9.82-rc.491

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 (473) 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 +220 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -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 +23 -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 +71 -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 +151 -0
  58. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  59. package/dist/commands/router.d.ts +203 -15
  60. package/dist/commands/upgrade-helper.d.ts +41 -1
  61. package/dist/config/chat-history.d.ts +11 -0
  62. package/dist/config/config.d.ts +19 -0
  63. package/dist/config/mesh-config.d.ts +66 -0
  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/config/state-store.d.ts +30 -0
  68. package/dist/daemon/dev-server.d.ts +0 -2
  69. package/dist/detection/cli-detector.d.ts +17 -0
  70. package/dist/detection/ide-detector.d.ts +13 -0
  71. package/dist/detection/win32-ide-version.d.ts +37 -0
  72. package/dist/git/change-impact-config.d.ts +159 -0
  73. package/dist/git/git-commands.d.ts +26 -2
  74. package/dist/git/git-diff.d.ts +6 -0
  75. package/dist/git/git-executor.d.ts +11 -0
  76. package/dist/git/git-status.d.ts +80 -0
  77. package/dist/git/git-types.d.ts +2 -50
  78. package/dist/git/git-worktree.d.ts +71 -1
  79. package/dist/git/index.d.ts +3 -1
  80. package/dist/index.d.ts +70 -17
  81. package/dist/index.js +53556 -19074
  82. package/dist/index.js.map +1 -1
  83. package/dist/index.mjs +53380 -19063
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/installer.d.ts +1 -4
  86. package/dist/ipc/local-ipc-server.d.ts +91 -0
  87. package/dist/launch.d.ts +1 -1
  88. package/dist/logging/async-batch-writer.d.ts +10 -0
  89. package/dist/logging/debug-config.d.ts +16 -0
  90. package/dist/logging/log-redactor.d.ts +24 -0
  91. package/dist/logging/log-tail-reader.d.ts +81 -0
  92. package/dist/logging/logger.d.ts +1 -1
  93. package/dist/mesh/contracts.d.ts +256 -0
  94. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  95. package/dist/mesh/coordinator-registry.d.ts +59 -0
  96. package/dist/mesh/mesh-active-work.d.ts +203 -0
  97. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  98. package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
  99. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  100. package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
  101. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  102. package/dist/mesh/mesh-event-forwarding.d.ts +58 -0
  103. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  104. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  105. package/dist/mesh/mesh-events-pending.d.ts +258 -0
  106. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  107. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  108. package/dist/mesh/mesh-events.d.ts +6 -49
  109. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  110. package/dist/mesh/mesh-host-ownership.d.ts +21 -1
  111. package/dist/mesh/mesh-init.d.ts +128 -0
  112. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  113. package/dist/mesh/mesh-ledger.d.ts +139 -1
  114. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  115. package/dist/mesh/mesh-missions.d.ts +281 -0
  116. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  117. package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
  118. package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
  119. package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
  120. package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
  121. package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
  122. package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
  123. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  124. package/dist/mesh/mesh-refine-gates.d.ts +457 -0
  125. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  126. package/dist/mesh/mesh-remote-event-pull.d.ts +15 -0
  127. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  128. package/dist/mesh/mesh-routing.d.ts +70 -0
  129. package/dist/mesh/mesh-runtime-store.d.ts +567 -0
  130. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  131. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  132. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  133. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +34 -0
  134. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  135. package/dist/mesh/mesh-work-queue.d.ts +392 -1
  136. package/dist/mesh/preview-freshness.d.ts +28 -0
  137. package/dist/mesh/refine-config.d.ts +97 -0
  138. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  139. package/dist/providers/acp-provider-instance.d.ts +5 -0
  140. package/dist/providers/approval-utils.d.ts +46 -0
  141. package/dist/providers/chat-message-normalization.d.ts +58 -1
  142. package/dist/providers/cli-provider-effect-format.d.ts +30 -0
  143. package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
  144. package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
  145. package/dist/providers/cli-provider-instance-types.d.ts +45 -0
  146. package/dist/providers/cli-provider-instance.d.ts +426 -30
  147. package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
  148. package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
  149. package/dist/providers/contracts.d.ts +196 -6
  150. package/dist/providers/external-sources.d.ts +71 -0
  151. package/dist/providers/manual-attendance.d.ts +79 -0
  152. package/dist/providers/native-history/antigravity-claim-registry.d.ts +39 -0
  153. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  154. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  155. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  156. package/dist/providers/native-history/constants.d.ts +12 -0
  157. package/dist/providers/native-history/dispatcher.d.ts +44 -0
  158. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  159. package/dist/providers/native-history/index.d.ts +13 -0
  160. package/dist/providers/provider-instance-manager.d.ts +30 -0
  161. package/dist/providers/provider-instance.d.ts +31 -1
  162. package/dist/providers/provider-loader.d.ts +42 -5
  163. package/dist/providers/provider-trust.d.ts +31 -0
  164. package/dist/providers/read-chat-contract.d.ts +29 -0
  165. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  166. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  167. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  168. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  169. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  170. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  171. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  172. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  173. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  174. package/dist/providers/sdk/v1/index.d.ts +30 -0
  175. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  176. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  177. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  178. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  179. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  180. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  181. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  182. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  183. package/dist/providers/spec/adapter.d.ts +98 -0
  184. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  185. package/dist/providers/spec/evaluator.d.ts +45 -0
  186. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  187. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  188. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  189. package/dist/providers/spec/fsm-types.d.ts +202 -0
  190. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  191. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  192. package/dist/providers/spec/route.d.ts +4 -0
  193. package/dist/providers/spec/types.d.ts +244 -0
  194. package/dist/providers/status-monitor.d.ts +7 -7
  195. package/dist/providers/transcript-v2.d.ts +176 -0
  196. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  197. package/dist/providers/working-dir.d.ts +17 -0
  198. package/dist/repo-mesh-types.d.ts +616 -12
  199. package/dist/runtime-defaults.d.ts +2 -0
  200. package/dist/session-host/managed-host.d.ts +64 -0
  201. package/dist/session-host/runtime-surface.d.ts +10 -16
  202. package/dist/sessions/registry.d.ts +26 -0
  203. package/dist/shared-types-extra.d.ts +2 -4
  204. package/dist/shared-types.d.ts +110 -55
  205. package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
  206. package/dist/status/normalize.d.ts +1 -1
  207. package/dist/status/normalize.js +1 -0
  208. package/dist/status/normalize.js.map +1 -1
  209. package/dist/status/normalize.mjs +1 -0
  210. package/dist/status/normalize.mjs.map +1 -1
  211. package/dist/status/reporter.d.ts +2 -0
  212. package/dist/status/snapshot.d.ts +27 -0
  213. package/dist/system/hash.d.ts +8 -0
  214. package/dist/system/load-better-sqlite3.d.ts +21 -0
  215. package/dist/types.d.ts +20 -6
  216. package/package.json +11 -4
  217. package/src/agent-stream/poller.ts +2 -3
  218. package/src/agent-stream/provider-adapter.ts +1 -1
  219. package/src/boot/daemon-lifecycle.ts +80 -14
  220. package/src/boot/process-hardening.ts +89 -0
  221. package/src/build-info.ts +73 -0
  222. package/src/chat/source-machine.ts +534 -0
  223. package/src/chat/source-resolver.ts +0 -0
  224. package/src/chat/subscription-updates.ts +20 -1
  225. package/src/cli-adapter-types.d.ts +3 -1
  226. package/src/cli-adapter-types.ts +68 -2
  227. package/src/cli-adapters/cli-script-runner.ts +421 -0
  228. package/src/cli-adapters/cli-state-engine.ts +1282 -0
  229. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  230. package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
  231. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  232. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  233. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  234. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  235. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  236. package/src/cli-adapters/pty-transport.ts +2 -1
  237. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  238. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  239. package/src/cli-adapters/resolve-executable.ts +204 -0
  240. package/src/cli-adapters/session-host-transport.ts +2 -1
  241. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  242. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  243. package/src/cli-adapters/terminal-screen.ts +16 -81
  244. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  245. package/src/commands/chat-commands-read.ts +2788 -0
  246. package/src/commands/chat-commands-scope.ts +54 -0
  247. package/src/commands/chat-commands-shared.ts +114 -0
  248. package/src/commands/chat-commands-write.ts +891 -0
  249. package/src/commands/chat-commands.ts +19 -1841
  250. package/src/commands/cli-manager.d.ts +2 -0
  251. package/src/commands/cli-manager.ts +724 -27
  252. package/src/commands/handler.ts +865 -2
  253. package/src/commands/high-family/index.ts +28 -0
  254. package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
  255. package/src/commands/high-family/mesh-events.ts +102 -0
  256. package/src/commands/high-family/mesh-status.ts +857 -0
  257. package/src/commands/high-family/types.ts +80 -0
  258. package/src/commands/low-family/coordinator-prompt.ts +125 -0
  259. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  260. package/src/commands/low-family/diagnostics.ts +57 -0
  261. package/src/commands/low-family/index.ts +37 -0
  262. package/src/commands/low-family/mesh-ledger.ts +62 -0
  263. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  264. package/src/commands/low-family/notification.ts +116 -0
  265. package/src/commands/low-family/refine-config.ts +106 -0
  266. package/src/commands/low-family/session-host.ts +282 -0
  267. package/src/commands/low-family/spec-providerdev.ts +217 -0
  268. package/src/commands/low-family/status-meta.ts +112 -0
  269. package/src/commands/low-family/types.ts +39 -0
  270. package/src/commands/med-family/cli-agent.ts +270 -0
  271. package/src/commands/med-family/fast-forward.ts +230 -0
  272. package/src/commands/med-family/ide.ts +163 -0
  273. package/src/commands/med-family/index.ts +37 -0
  274. package/src/commands/med-family/mesh-crud.ts +1309 -0
  275. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  276. package/src/commands/med-family/mesh-queue.ts +167 -0
  277. package/src/commands/med-family/mesh-restart.ts +92 -0
  278. package/src/commands/med-family/types.ts +153 -0
  279. package/src/commands/mesh-coordinator.ts +334 -124
  280. package/src/commands/router-aggregate-status.ts +209 -0
  281. package/src/commands/router-mesh-session-owner.ts +114 -0
  282. package/src/commands/router-refine.ts +1794 -0
  283. package/src/commands/router-worktree-cleanup.ts +870 -0
  284. package/src/commands/router.ts +567 -4149
  285. package/src/commands/stream-commands.ts +8 -0
  286. package/src/commands/upgrade-helper.ts +310 -45
  287. package/src/config/chat-history.ts +517 -24
  288. package/src/config/config.ts +30 -0
  289. package/src/config/mesh-config.ts +300 -24
  290. package/src/config/mesh-json-config.ts +376 -0
  291. package/src/config/recent-activity.ts +8 -2
  292. package/src/config/registry-resolver.ts +100 -0
  293. package/src/config/repo-settings.ts +111 -0
  294. package/src/config/state-store.ts +55 -0
  295. package/src/daemon/dev-auto-implement.ts +3 -2
  296. package/src/daemon/dev-cli-debug.ts +10 -1
  297. package/src/daemon/dev-server.ts +0 -541
  298. package/src/detection/cli-detector.ts +94 -9
  299. package/src/detection/ide-detector.ts +55 -16
  300. package/src/detection/win32-ide-version.ts +106 -0
  301. package/src/git/change-impact-config.ts +354 -0
  302. package/src/git/git-commands.ts +112 -16
  303. package/src/git/git-diff.ts +81 -11
  304. package/src/git/git-executor.ts +12 -0
  305. package/src/git/git-status.ts +822 -48
  306. package/src/git/git-types.ts +14 -62
  307. package/src/git/git-worktree.ts +261 -4
  308. package/src/git/index.ts +17 -0
  309. package/src/index.ts +190 -13
  310. package/src/installer.d.ts +1 -1
  311. package/src/installer.ts +8 -6
  312. package/src/ipc/local-ipc-server.ts +278 -0
  313. package/src/launch.d.ts +1 -1
  314. package/src/launch.ts +37 -28
  315. package/src/logging/async-batch-writer.ts +55 -0
  316. package/src/logging/command-log.ts +7 -5
  317. package/src/logging/debug-config.ts +25 -0
  318. package/src/logging/debug-trace.ts +7 -2
  319. package/src/logging/log-redactor.ts +100 -0
  320. package/src/logging/log-tail-reader.ts +341 -0
  321. package/src/logging/logger.ts +14 -7
  322. package/src/mesh/contracts.ts +510 -0
  323. package/src/mesh/coordinator-prompt.ts +627 -34
  324. package/src/mesh/coordinator-registry.ts +121 -0
  325. package/src/mesh/mesh-active-work.ts +706 -0
  326. package/src/mesh/mesh-clone-grace.ts +68 -0
  327. package/src/mesh/mesh-completion-synthesis.ts +416 -0
  328. package/src/mesh/mesh-coordinator-config.ts +97 -0
  329. package/src/mesh/mesh-delivery-policy.ts +284 -0
  330. package/src/mesh/mesh-event-classify.ts +78 -0
  331. package/src/mesh/mesh-event-forwarding.ts +2030 -0
  332. package/src/mesh/mesh-event-trace.ts +67 -0
  333. package/src/mesh/mesh-events-coordinator.ts +32 -0
  334. package/src/mesh/mesh-events-pending.ts +1548 -0
  335. package/src/mesh/mesh-events-stale.ts +452 -0
  336. package/src/mesh/mesh-events-utils.ts +443 -0
  337. package/src/mesh/mesh-events.ts +43 -1035
  338. package/src/mesh/mesh-fast-forward.ts +856 -0
  339. package/src/mesh/mesh-host-ownership.ts +41 -3
  340. package/src/mesh/mesh-init.ts +350 -0
  341. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  342. package/src/mesh/mesh-ledger.ts +897 -102
  343. package/src/mesh/mesh-magi-status.ts +223 -0
  344. package/src/mesh/mesh-missions.ts +695 -0
  345. package/src/mesh/mesh-node-identity.ts +2065 -0
  346. package/src/mesh/mesh-queue-assignment.ts +2498 -0
  347. package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
  348. package/src/mesh/mesh-reconcile-config.ts +66 -0
  349. package/src/mesh/mesh-reconcile-identity.ts +103 -0
  350. package/src/mesh/mesh-reconcile-loop.ts +1696 -0
  351. package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
  352. package/src/mesh/mesh-refine-batch.ts +205 -0
  353. package/src/mesh/mesh-refine-gates.ts +1792 -0
  354. package/src/mesh/mesh-refine-status.ts +231 -0
  355. package/src/mesh/mesh-remote-event-pull.ts +279 -0
  356. package/src/mesh/mesh-review-inbox.ts +308 -0
  357. package/src/mesh/mesh-routing.ts +291 -0
  358. package/src/mesh/mesh-runtime-store.ts +2292 -0
  359. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  360. package/src/mesh/mesh-task-inflight.ts +70 -0
  361. package/src/mesh/mesh-task-stats.ts +161 -0
  362. package/src/mesh/mesh-unresolved-forward-outbox.ts +215 -0
  363. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  364. package/src/mesh/mesh-work-queue.ts +1489 -145
  365. package/src/mesh/preview-freshness.ts +163 -0
  366. package/src/mesh/refine-config.ts +129 -12
  367. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  368. package/src/providers/acp-provider-instance.ts +43 -10
  369. package/src/providers/approval-utils.d.ts +5 -0
  370. package/src/providers/approval-utils.ts +100 -6
  371. package/src/providers/chat-message-normalization.ts +126 -4
  372. package/src/providers/cli-provider-effect-format.ts +53 -0
  373. package/src/providers/cli-provider-history-dedup.ts +75 -0
  374. package/src/providers/cli-provider-input-prompt.ts +133 -0
  375. package/src/providers/cli-provider-instance-types.ts +131 -0
  376. package/src/providers/cli-provider-instance.ts +2771 -499
  377. package/src/providers/cli-provider-status-helpers.ts +123 -0
  378. package/src/providers/cli-provider-transcript-merge.ts +114 -0
  379. package/src/providers/contracts.d.ts +55 -0
  380. package/src/providers/contracts.ts +207 -6
  381. package/src/providers/extension-provider-instance.ts +12 -7
  382. package/src/providers/external-sources.ts +218 -0
  383. package/src/providers/ide-provider-instance.ts +35 -12
  384. package/src/providers/manual-attendance.ts +105 -0
  385. package/src/providers/native-history/antigravity-claim-registry.ts +138 -0
  386. package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -0
  387. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  388. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  389. package/src/providers/native-history/constants.ts +19 -0
  390. package/src/providers/native-history/dispatcher.ts +617 -0
  391. package/src/providers/native-history/hermes-cli-transcript.ts +312 -0
  392. package/src/providers/native-history/index.ts +30 -0
  393. package/src/providers/provider-instance-manager.ts +71 -0
  394. package/src/providers/provider-instance.ts +24 -1
  395. package/src/providers/provider-loader.ts +700 -55
  396. package/src/providers/provider-schema.ts +93 -14
  397. package/src/providers/provider-trust.ts +114 -0
  398. package/src/providers/read-chat-contract.ts +76 -16
  399. package/src/providers/sdk/README.md +49 -0
  400. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  401. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  402. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  403. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  404. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  405. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  406. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  407. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  408. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  409. package/src/providers/sdk/v1/index.ts +152 -0
  410. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  411. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  412. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  413. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +538 -0
  414. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  415. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  416. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  417. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  418. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  419. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  420. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  421. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  422. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  423. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  424. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  425. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  426. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  427. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  428. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  429. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  430. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  431. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  432. package/src/providers/sdk/v1/validators/index.ts +19 -0
  433. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  434. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  435. package/src/providers/spec/adapter.ts +246 -0
  436. package/src/providers/spec/cli-adapter.ts +1064 -0
  437. package/src/providers/spec/evaluator.ts +407 -0
  438. package/src/providers/spec/fsm-driver.ts +1528 -0
  439. package/src/providers/spec/fsm-evaluator.ts +290 -0
  440. package/src/providers/spec/fsm-loader.ts +128 -0
  441. package/src/providers/spec/fsm-types.ts +301 -0
  442. package/src/providers/spec/native-history-executor.ts +1241 -0
  443. package/src/providers/spec/pre-launch-trust.ts +104 -0
  444. package/src/providers/spec/route.ts +51 -0
  445. package/src/providers/spec/types.ts +284 -0
  446. package/src/providers/status-monitor.d.ts +7 -7
  447. package/src/providers/status-monitor.ts +37 -22
  448. package/src/providers/transcript-v2.ts +567 -0
  449. package/src/providers/types/interactive-prompt.ts +536 -0
  450. package/src/providers/version-archive.ts +64 -24
  451. package/src/providers/working-dir.ts +23 -0
  452. package/src/repo-mesh-types.ts +861 -14
  453. package/src/runtime-defaults.ts +39 -0
  454. package/src/session-host/managed-host.ts +218 -0
  455. package/src/session-host/runtime-surface.ts +20 -80
  456. package/src/sessions/registry.ts +44 -0
  457. package/src/shared-types-extra.ts +2 -4
  458. package/src/shared-types.d.ts +8 -0
  459. package/src/shared-types.ts +148 -55
  460. package/src/status/builders.ts +69 -6
  461. package/src/status/chat-tail-hot-sessions.ts +117 -2
  462. package/src/status/normalize.ts +2 -0
  463. package/src/status/reporter.ts +19 -1
  464. package/src/status/snapshot.ts +100 -27
  465. package/src/system/hash.ts +23 -0
  466. package/src/system/host-memory.ts +29 -12
  467. package/src/system/load-better-sqlite3.ts +68 -0
  468. package/src/types.ts +26 -6
  469. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  470. package/dist/mesh/mesh-sync.d.ts +0 -53
  471. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  472. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  473. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,617 @@
1
+ /**
2
+ * Spec-aware dispatcher for native conversation history.
3
+ *
4
+ * The four existing readers (claude/codex/antigravity/hermes) already know
5
+ * how to parse each agent's on-disk format. This dispatcher just resolves
6
+ * the right file given a workspace + sessionId hint, then hands it off.
7
+ *
8
+ * Wired into ProviderModule.scripts.readNativeHistory by provider-loader
9
+ * when spec.json declares native_history.reader. The script signature
10
+ * matches what chat-history.ts expects (see callProviderNativeHistoryRead).
11
+ */
12
+ 'use strict';
13
+
14
+ import * as fs from 'node:fs';
15
+ import * as os from 'node:os';
16
+ import * as path from 'node:path';
17
+ import { readSession as readClaudeCliSession } from './claude-cli-transcript.js';
18
+ import { readSession as readCodexCliSession } from './codex-cli-transcript.js';
19
+ import { readSession as readAntigravityCliSession } from './antigravity-cli-transcript.js';
20
+ import { readSession as readHermesCliSession } from './hermes-cli-transcript.js';
21
+ import { SPAWN_BIND_GRACE_MS } from './constants.js';
22
+ import {
23
+ antigravityOwnerToken,
24
+ claimAntigravityConversation,
25
+ isAntigravityConversationClaimedByOther,
26
+ } from './antigravity-claim-registry.js';
27
+
28
+ export type ReaderId = 'claude-cli' | 'codex-cli' | 'antigravity-cli' | 'hermes-cli';
29
+
30
+ export interface NativeHistoryInput {
31
+ agentType?: string;
32
+ sessionId?: string;
33
+ providerSessionId?: string;
34
+ historySessionId?: string;
35
+ /** Daemon instance id of the reading session. Used (with workspace +
36
+ * sessionStartedAtMs) to derive the antigravity conversation-claim owner
37
+ * token so two concurrent sessions never bind to the same .db. */
38
+ instanceId?: string;
39
+ workspace?: string;
40
+ sessionStartedAtMs?: number;
41
+ format?: string;
42
+ watchPath?: string;
43
+ forceRefresh?: boolean;
44
+ args?: Record<string, unknown>;
45
+ }
46
+
47
+ export interface NativeHistoryResult {
48
+ messages: Array<{ role: string; content: string; receivedAt?: number; kind?: string; workspace?: string }>;
49
+ providerSessionId?: string;
50
+ sourcePath: string;
51
+ sourceMtimeMs: number;
52
+ nativeHistoryCoverage?: 'full' | 'partial' | 'best-effort';
53
+ /**
54
+ * True only when the resolved conversation is confirmed to belong to THIS
55
+ * reading session by the owner-token identity (an exact uuid bind, or a
56
+ * spawn-floor/birth-time pick born after this session started). False for a
57
+ * bare recency/newest-by-mtime pick made with no spawn floor — that pick may
58
+ * alias a co-located concurrent session (the antigravity coordinator↔replica
59
+ * crosswire), so its uuid must NEVER be recorded as a pin nor trusted to
60
+ * satisfy the same-pass safe-mapping identity check. Read-path callers gate
61
+ * the workspace-latest pin + first-read trust on this flag. Non-antigravity
62
+ * readers leave it undefined (their existing exact-file resolution is
63
+ * unaffected by this signal).
64
+ */
65
+ ownerConfirmed?: boolean;
66
+ }
67
+
68
+ export function createNativeHistoryDispatcher(reader: ReaderId): (input: NativeHistoryInput) => NativeHistoryResult | null {
69
+ return (input: NativeHistoryInput) => {
70
+ const workspace = input.workspace || '';
71
+ const sessionId = input.sessionId || input.historySessionId || '';
72
+ // Caller may pass a providerSessionId (the *provider's own* id, e.g.
73
+ // the uuid claude writes into the jsonl basename). When present, the
74
+ // dispatcher only returns a transcript whose file id matches —
75
+ // otherwise the newest_by_mtime fallback can surface a different
76
+ // session's chat (round 9 part b: the user reported "previous chat
77
+ // shows up before I type anything" on every provider).
78
+ const requestedProviderSid = input.providerSessionId || '';
79
+
80
+ const sessionStartedAtMs = typeof input.sessionStartedAtMs === 'number'
81
+ ? input.sessionStartedAtMs
82
+ : typeof input.args?.sessionStartedAtMs === 'number'
83
+ ? input.args.sessionStartedAtMs
84
+ : 0;
85
+ const instanceId = typeof input.instanceId === 'string'
86
+ ? input.instanceId
87
+ : typeof input.args?.instanceId === 'string'
88
+ ? (input.args.instanceId as string)
89
+ : '';
90
+ const resolved = resolveSourcePath(reader, workspace, sessionId, sessionStartedAtMs, instanceId);
91
+ const sourcePath = resolved?.path || null;
92
+ if (!sourcePath) return null;
93
+ // Owner-confirmation only meaningful for antigravity (see resolveAntigravityPath).
94
+ // For other readers the file was resolved by exact per-session key already;
95
+ // leave the flag undefined so the read-path callers treat them as before.
96
+ const ownerConfirmed = reader === 'antigravity-cli' ? resolved?.ownerConfirmed === true : undefined;
97
+ if (input.forceRefresh === true || input.args?.forceRefresh === true) {
98
+ try { fs.statSync(sourcePath); } catch { /* best-effort metadata refresh */ }
99
+ }
100
+
101
+ const session = readByReader(reader, sourcePath, sessionId, workspace, requestedProviderSid);
102
+ if (!session) return null;
103
+
104
+ if (requestedProviderSid && session.providerSessionId && session.providerSessionId !== requestedProviderSid) {
105
+ return null;
106
+ }
107
+
108
+ // For antigravity, the authoritative conversation id is the on-disk uuid
109
+ // embedded in the resolved path (conversations/<uuid>.db or
110
+ // brain/<uuid>/…/transcript.jsonl), NOT the ADHDev session id the caller
111
+ // threaded in. Surface that uuid as providerSessionId whenever the reader
112
+ // did not already return a distinct one, so the read_chat layer can pin
113
+ // the real conversation and (post-restart) exact-bind straight to it
114
+ // instead of re-running the mtime/recency heuristic that drops an idle
115
+ // store (ANTIGRAVITY-FINAL-MESSAGE-TAIL-GAP). Other providers keep the
116
+ // reader's value verbatim.
117
+ let resolvedProviderSessionId = session.providerSessionId;
118
+ if (reader === 'antigravity-cli') {
119
+ const onDiskUuid = extractAntigravityConversationUuid(session.sourcePath || sourcePath);
120
+ if (onDiskUuid && (!resolvedProviderSessionId || resolvedProviderSessionId === sessionId)) {
121
+ resolvedProviderSessionId = onDiskUuid;
122
+ }
123
+ }
124
+
125
+ return {
126
+ messages: session.messages.map((m: any) => ({
127
+ role: normalizeRole(m.role),
128
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
129
+ receivedAt: typeof m.receivedAt === 'number' ? m.receivedAt : Date.parse(m.timestamp || '') || Date.now(),
130
+ kind: typeof m.kind === 'string' ? m.kind : 'standard',
131
+ workspace: typeof m.workspace === 'string' ? m.workspace : workspace || undefined,
132
+ })),
133
+ providerSessionId: resolvedProviderSessionId,
134
+ sourcePath: session.sourcePath,
135
+ sourceMtimeMs: session.sourceMtimeMs,
136
+ nativeHistoryCoverage: (session as any).nativeHistoryCoverage || 'full',
137
+ ownerConfirmed,
138
+ };
139
+ };
140
+ }
141
+
142
+ // ────────────────────────────────────────────────────────────────────────────
143
+ // Per-provider path resolution
144
+ // ────────────────────────────────────────────────────────────────────────────
145
+
146
+ interface ResolvedSource {
147
+ path: string;
148
+ /** Antigravity only: whether the resolution was owner-token-confirmed (see
149
+ * NativeHistoryResult.ownerConfirmed / resolveAntigravityPath). */
150
+ ownerConfirmed?: boolean;
151
+ }
152
+
153
+ function resolveSourcePath(reader: ReaderId, workspace: string, sessionId: string, sessionStartedAtMs: number, instanceId: string): ResolvedSource | null {
154
+ switch (reader) {
155
+ case 'claude-cli': { const p = resolveClaudePath(workspace, sessionId); return p ? { path: p } : null; }
156
+ case 'codex-cli': { const p = resolveCodexPath(workspace, sessionId, sessionStartedAtMs); return p ? { path: p } : null; }
157
+ case 'antigravity-cli': return resolveAntigravityPath(workspace, sessionId, sessionStartedAtMs, instanceId);
158
+ case 'hermes-cli': { const p = resolveHermesPath(workspace, sessionId); return p ? { path: p } : null; }
159
+ }
160
+ }
161
+
162
+ function resolveClaudePath(workspace: string, sessionId: string): string | null {
163
+ // claude stores per-cwd: ~/.claude/projects/<cwd-as-dashes>/<uuid>.jsonl
164
+ const dir = path.join(os.homedir(), '.claude', 'projects', cwdAsDashes(workspace));
165
+ if (!fs.existsSync(dir)) return null;
166
+ if (sessionId) {
167
+ const candidate = path.join(dir, `${sessionId}.jsonl`);
168
+ if (fs.existsSync(candidate)) return candidate;
169
+ }
170
+ // No exact match: return null. The newest_by_mtime fallback used to
171
+ // grab whichever transcript was touched most recently, but that
172
+ // surfaced a different (often the user's *external* claude session
173
+ // in the same workspace) chat in the dashboard before the user
174
+ // typed anything. The right answer is to show nothing until either
175
+ // the daemon's sessionId actually maps to a file or the caller
176
+ // passes the correct providerSessionId (round 9 part b).
177
+ return null;
178
+ }
179
+
180
+ function resolveCodexPath(workspace: string, sessionId: string, sessionStartedAtMs: number): string | null {
181
+ // codex stores by UTC date: ~/.codex/sessions/<year>/<month>/<day>/<file>.jsonl
182
+ const root = codexSessionsRoot();
183
+ if (sessionId && isUuidLikeSessionId(sessionId)) {
184
+ return findCodexPathBySessionId(root, sessionId);
185
+ }
186
+ return findCodexPathByRuntime(root, workspace, sessionStartedAtMs);
187
+ }
188
+
189
+ function findCodexPathBySessionId(root: string, sessionId: string): string | null {
190
+ if (!fs.existsSync(root)) return null;
191
+ const needle = sessionId.toLowerCase();
192
+ const matches: Array<{ p: string; mtime: number }> = [];
193
+ const stack: string[] = [root];
194
+ while (stack.length > 0) {
195
+ const current = stack.pop()!;
196
+ let entries: fs.Dirent[] = [];
197
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
198
+ for (const entry of entries) {
199
+ const entryPath = path.join(current, entry.name);
200
+ if (entry.isDirectory()) {
201
+ stack.push(entryPath);
202
+ continue;
203
+ }
204
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
205
+ if (!entry.name.toLowerCase().includes(needle)) continue;
206
+ if (!isSafeFilename(entry.name.replace('.jsonl', ''))) continue;
207
+ matches.push({ p: entryPath, mtime: safeMtime(entryPath) });
208
+ }
209
+ }
210
+ matches.sort((a, b) => b.mtime - a.mtime);
211
+ return matches[0]?.p ?? null;
212
+ }
213
+
214
+ function findCodexPathByRuntime(root: string, workspace: string, sessionStartedAtMs: number): string | null {
215
+ if (!fs.existsSync(root) || !workspace) return null;
216
+ const workspaceResolved = resolveRealPath(workspace);
217
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
218
+ const matches: Array<{ p: string; mtime: number; diff: number }> = [];
219
+ const stack: string[] = [root];
220
+
221
+ while (stack.length > 0) {
222
+ const current = stack.pop()!;
223
+ let entries: fs.Dirent[] = [];
224
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
225
+ for (const entry of entries) {
226
+ const entryPath = path.join(current, entry.name);
227
+ if (entry.isDirectory()) {
228
+ stack.push(entryPath);
229
+ continue;
230
+ }
231
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
232
+ const mtime = safeMtime(entryPath);
233
+ if (mtime < cutoff) continue;
234
+ const meta = readCodexSessionMeta(entryPath);
235
+ if (!meta?.cwd || resolveRealPath(meta.cwd) !== workspaceResolved) continue;
236
+ const diff = sessionStartedAtMs > 0 && meta.timestampMs != null
237
+ ? Math.abs(meta.timestampMs - sessionStartedAtMs)
238
+ : 0;
239
+ if (sessionStartedAtMs > 0 && (meta.timestampMs == null || diff > SPAWN_BIND_GRACE_MS)) continue;
240
+ matches.push({ p: entryPath, mtime, diff });
241
+ }
242
+ }
243
+
244
+ matches.sort((a, b) => sessionStartedAtMs > 0
245
+ ? a.diff - b.diff || b.mtime - a.mtime
246
+ : b.mtime - a.mtime);
247
+ return matches[0]?.p ?? null;
248
+ }
249
+
250
+ function readCodexSessionMeta(filePath: string): { cwd?: string; timestampMs?: number } | null {
251
+ try {
252
+ const fd = fs.openSync(filePath, 'r');
253
+ try {
254
+ const buffer = Buffer.alloc(8192);
255
+ const bytes = fs.readSync(fd, buffer, 0, buffer.length, 0);
256
+ if (bytes <= 0) return null;
257
+ const text = buffer.subarray(0, bytes).toString('utf8');
258
+ const firstLine = text.slice(0, text.indexOf('\n') >= 0 ? text.indexOf('\n') : text.length).trim();
259
+ if (!firstLine) return null;
260
+ const record = JSON.parse(firstLine) as Record<string, unknown>;
261
+ if (record.type !== 'session_meta' || !record.payload || typeof record.payload !== 'object') return null;
262
+ const payload = record.payload as Record<string, unknown>;
263
+ const timestampRaw = payload.timestamp;
264
+ const timestampMs = typeof timestampRaw === 'string'
265
+ ? Date.parse(timestampRaw)
266
+ : typeof timestampRaw === 'number'
267
+ ? (timestampRaw < 1e12 ? timestampRaw * 1000 : timestampRaw)
268
+ : NaN;
269
+ return {
270
+ cwd: typeof payload.cwd === 'string' ? payload.cwd : undefined,
271
+ timestampMs: Number.isFinite(timestampMs) ? timestampMs : undefined,
272
+ };
273
+ } finally {
274
+ fs.closeSync(fd);
275
+ }
276
+ } catch {
277
+ return null;
278
+ }
279
+ }
280
+
281
+ function resolveRealPath(value: string): string {
282
+ try { return fs.realpathSync(value); } catch { return value; }
283
+ }
284
+
285
+ /**
286
+ * Pull the antigravity conversation uuid out of a resolved source path. Both
287
+ * on-disk layouts embed it: conversations/<uuid>.db and
288
+ * brain/<uuid>/.system_generated/logs/transcript*.jsonl (and the legacy
289
+ * conversations/<uuid>.pb). Returns the uuid when a segment matches the
290
+ * canonical form, else ''.
291
+ */
292
+ function extractAntigravityConversationUuid(sourcePath: string): string {
293
+ if (!sourcePath) return '';
294
+ const segments = sourcePath.split(/[\\/]/);
295
+ // conversations/<uuid>.db|.pb — the basename minus extension.
296
+ const base = segments[segments.length - 1] || '';
297
+ const baseMatch = /^([0-9a-f-]+)\.(?:db|pb)$/i.exec(base);
298
+ if (baseMatch && isUuidLikeSessionId(baseMatch[1])) return baseMatch[1];
299
+ // brain/<uuid>/… — the first uuid-like path segment.
300
+ for (const seg of segments) {
301
+ if (isUuidLikeSessionId(seg)) return seg;
302
+ }
303
+ return '';
304
+ }
305
+
306
+ /**
307
+ * The daemon may stamp a session's spawn time a hair before the CLI child
308
+ * actually creates its conversation .db, so treat a store born within this
309
+ * grace of the spawn floor as still belonging to this session. Kept small
310
+ * (< a typical concurrent-spawn gap) so a sibling's PRE-spawn store is still
311
+ * excluded rather than mis-bound.
312
+ */
313
+ const AGY_SPAWN_CLAIM_GRACE_MS = 2000;
314
+
315
+ function resolveAntigravityPath(
316
+ workspace: string,
317
+ sessionId: string,
318
+ sessionStartedAtMs: number,
319
+ instanceId: string,
320
+ ): ResolvedSource | null {
321
+ const agyRoot = path.join(os.homedir(), '.gemini', 'antigravity-cli');
322
+ // Owner token identifies THIS reading session. The provider instance derives
323
+ // the identical token (workspace + startedAt, or instanceId) so it can
324
+ // release these claims on shutdown. '' when there is no stable identity to
325
+ // key on — claiming is then skipped but exclusion still runs.
326
+ const owner = antigravityOwnerToken(workspace, sessionStartedAtMs, instanceId);
327
+
328
+ // (1) Exact session bind + LOCK: current antigravity writes a per-session
329
+ // SQLite db at conversations/<uuid>.db. Once the caller knows the session
330
+ // id, bind straight to it — this is authoritative and never re-resolves
331
+ // by mtime, so an already-bound session cannot be hijacked by a newer
332
+ // .db on a later read. Claim it so a concurrent unbound sibling can never
333
+ // grab this same conversation.
334
+ if (sessionId && isUuidLikeSessionId(sessionId)) {
335
+ const dbPath = path.join(agyRoot, 'conversations', `${sessionId}.db`);
336
+ if (fs.existsSync(dbPath)) {
337
+ if (owner) claimAntigravityConversation(sessionId, owner);
338
+ // Exact uuid bind — the caller named this conversation, so it is
339
+ // authoritatively this session's own. Owner-confirmed.
340
+ return { path: dbPath, ownerConfirmed: true };
341
+ }
342
+ }
343
+
344
+ // (2) brain/<uuid>/.system_generated/logs/transcript.jsonl (legacy full source).
345
+ // Only bind to a brain transcript that is NON-EMPTY (antigravity may leave
346
+ // it 0 bytes when the real data lives in the per-session .db). Exclude any
347
+ // brain conversation already claimed by a DIFFERENT live session.
348
+ //
349
+ // Selection MUST mirror pickUnboundConversationDb (step 3): when a spawn
350
+ // floor is known, a brain dir born at/after the floor is THIS session's own,
351
+ // and among those the OLDEST-created wins (the store created first after the
352
+ // session started). The previous newest-by-mtime sort silently mis-bound: in
353
+ // a MAGI panel every co-located antigravity session (coordinator + replicas)
354
+ // has a non-empty brain transcript, and the replica that finished its turn
355
+ // last has the newest mtime — so a coordinator's read grabbed the replica's
356
+ // transcript here, BEFORE step 3's floor-aware pick could run. That is the
357
+ // antigravity coordinator↔replica crosswire, and it lives in THIS step, not
358
+ // step 3. Keep newest-by-mtime only in the floor-less legacy path.
359
+ const brainRoot = path.join(agyRoot, 'brain');
360
+ if (fs.existsSync(brainRoot)) {
361
+ const cutoff = spawnAwareCutoff(sessionStartedAtMs);
362
+ const nonEmptyBrain = (uuid: string, p: string): string | null => {
363
+ const t = path.join(p, '.system_generated', 'logs', 'transcript.jsonl');
364
+ return (fs.existsSync(t) && safeSize(t) > 0) ? t : null;
365
+ };
366
+ const all = fs.readdirSync(brainRoot, { withFileTypes: true })
367
+ .filter(e => e.isDirectory() && isUuidLikeSessionId(e.name))
368
+ .filter(e => !isAntigravityConversationClaimedByOther(e.name, owner))
369
+ .map(e => {
370
+ const p = path.join(brainRoot, e.name);
371
+ return { uuid: e.name, p, mtime: safeMtime(p), birth: safeBirthtime(p) };
372
+ })
373
+ .filter(e => e.mtime >= cutoff);
374
+ let ordered: Array<{ uuid: string; p: string }> = [];
375
+ // Floor branch (sessionStartedAtMs > 0) is birth-confirmed as this
376
+ // session's own store → owner-confirmed. Floor-less newest-by-mtime is a
377
+ // bare recency pick that can alias a co-located session → NOT confirmed.
378
+ const brainOwnerConfirmed = sessionStartedAtMs > 0;
379
+ if (sessionStartedAtMs > 0) {
380
+ // Floor branch: this session's own = born at/after (floor - grace),
381
+ // oldest-birth first. Mirrors pickUnboundConversationDb exactly so the
382
+ // two steps can never resolve DIFFERENT conversations for one session.
383
+ const floor = sessionStartedAtMs - AGY_SPAWN_CLAIM_GRACE_MS;
384
+ ordered = all
385
+ .filter(e => (e.birth > 0 ? e.birth : e.mtime) >= floor)
386
+ .sort((a, b) => (a.birth || a.mtime) - (b.birth || b.mtime));
387
+ } else {
388
+ // Floor-less legacy/unpinned discovery: newest-by-mtime (single-session).
389
+ ordered = [...all].sort((a, b) => b.mtime - a.mtime);
390
+ }
391
+ for (const e of ordered) {
392
+ const t = nonEmptyBrain(e.uuid, e.p);
393
+ if (t) {
394
+ if (owner) claimAntigravityConversation(e.uuid, owner);
395
+ return { path: t, ownerConfirmed: brainOwnerConfirmed };
396
+ }
397
+ }
398
+ }
399
+
400
+ // (3) No brain transcript and no bound session id: pick a conversations/<uuid>.db
401
+ // that is NOT claimed by another live session, guarded by this session's
402
+ // spawn time so we never mis-bind to a sibling's earlier store.
403
+ const convRoot = path.join(agyRoot, 'conversations');
404
+ const picked = pickUnboundConversationDb(convRoot, sessionStartedAtMs, owner);
405
+ if (picked) {
406
+ if (owner) claimAntigravityConversation(picked.uuid, owner);
407
+ return { path: picked.path, ownerConfirmed: picked.ownerConfirmed };
408
+ }
409
+
410
+ return null;
411
+ }
412
+
413
+ /**
414
+ * Choose the conversations/<uuid>.db for an as-yet-unbound antigravity session.
415
+ *
416
+ * Two isolation rules keep concurrent sessions apart:
417
+ * - claim exclusion: skip any .db already owned by a DIFFERENT live session,
418
+ * so two sessions can never resolve to the same conversation;
419
+ * - spawn-window guard: a session's own store is created at/after it spawned,
420
+ * so when a spawn floor is known, only stores born at/after (floor - grace)
421
+ * are eligible. A store that predates this session's spawn belongs to an
422
+ * earlier session and is never bound — if none qualifies we return null
423
+ * (native_history_empty) and let the caller retry once this session's own
424
+ * store appears, rather than binding a sibling's conversation.
425
+ *
426
+ * Among eligible unclaimed stores the OLDEST-created wins: in the normal case
427
+ * (each session polls native history only after its own store exists, and an
428
+ * earlier-spawned session polls earlier) this hands each session the first
429
+ * store created after it started — its own. When no spawn floor is available
430
+ * (legacy/unpinned discovery) we fall back to newest-by-mtime within the
431
+ * recency window, preserving the original single-session behaviour.
432
+ */
433
+ function pickUnboundConversationDb(
434
+ convRoot: string,
435
+ sessionFloorMs: number,
436
+ owner: string,
437
+ ): { path: string; uuid: string; ownerConfirmed: boolean } | null {
438
+ let entries: fs.Dirent[] = [];
439
+ try { entries = fs.readdirSync(convRoot, { withFileTypes: true }); } catch { return null; }
440
+
441
+ // A known spawn floor already pins a candidate to THIS session by birth time
442
+ // (a store created at/after the session spawned is its own). Once that floor
443
+ // is available, the recency window is not just unnecessary but harmful: an
444
+ // antigravity session that has sat idle longer than RECENT_WINDOW_MS still
445
+ // owns its conversation .db, but the recency cutoff would drop it from the
446
+ // candidate set, collapsing the read to native_history_empty and forcing the
447
+ // dashboard onto the PTY parse (user echo only, assistant tail lost —
448
+ // ANTIGRAVITY-FINAL-MESSAGE-TAIL-GAP, most visible right after a daemon
449
+ // restart clears the in-memory read pin). So only apply the recency cutoff in
450
+ // the floor-less (legacy/unpinned) discovery path, where it is the sole guard
451
+ // against binding an unrelated old store. When a floor is known the birth-time
452
+ // filter below is the authoritative, idle-agnostic owner check.
453
+ const applyRecencyCutoff = !(sessionFloorMs > 0);
454
+ const recencyCutoff = Date.now() - RECENT_WINDOW_MS;
455
+ const candidates: Array<{ path: string; uuid: string; mtime: number; birth: number }> = [];
456
+ for (const entry of entries) {
457
+ if (!entry.isFile()) continue;
458
+ const match = /^([0-9a-f-]+)\.db$/i.exec(entry.name);
459
+ if (!match || !isUuidLikeSessionId(match[1])) continue;
460
+ const uuid = match[1];
461
+ // (isolation) never consider a conversation a different live session owns.
462
+ if (isAntigravityConversationClaimedByOther(uuid, owner)) continue;
463
+ const p = path.join(convRoot, entry.name);
464
+ const mtime = safeMtime(p);
465
+ if (applyRecencyCutoff && mtime < recencyCutoff) continue;
466
+ candidates.push({ path: p, uuid, mtime, birth: safeBirthtime(p) });
467
+ }
468
+ if (candidates.length === 0) return null;
469
+
470
+ if (sessionFloorMs > 0) {
471
+ const floor = sessionFloorMs - AGY_SPAWN_CLAIM_GRACE_MS;
472
+ const own = candidates.filter(c => (c.birth > 0 ? c.birth : c.mtime) >= floor);
473
+ // A store created before this session spawned belongs to an earlier
474
+ // session — do NOT bind to it. Wait for our own store on the next read.
475
+ if (own.length === 0) return null;
476
+ own.sort((a, b) => (a.birth || a.mtime) - (b.birth || b.mtime));
477
+ // Birth-time confirmed as this session's own store → owner-confirmed.
478
+ return { path: own[0].path, uuid: own[0].uuid, ownerConfirmed: true };
479
+ }
480
+
481
+ // Floor-less newest-by-mtime: a bare recency pick with no per-session
482
+ // guarantee — it can alias a co-located concurrent session, so it is NOT
483
+ // owner-confirmed and must not be pinned/trusted by the read-path callers.
484
+ candidates.sort((a, b) => b.mtime - a.mtime);
485
+ return { path: candidates[0].path, uuid: candidates[0].uuid, ownerConfirmed: false };
486
+ }
487
+
488
+ /**
489
+ * mtime floor for the brain-transcript scan: the later of the recency window
490
+ * and this session's spawn floor (minus the claim grace), so a fresh read
491
+ * cannot surface a brain dir last touched before this session started.
492
+ */
493
+ function spawnAwareCutoff(sessionStartedAtMs: number): number {
494
+ const recency = Date.now() - RECENT_WINDOW_MS;
495
+ if (sessionStartedAtMs > 0) return Math.max(recency, sessionStartedAtMs - AGY_SPAWN_CLAIM_GRACE_MS);
496
+ return recency;
497
+ }
498
+
499
+ function resolveHermesPath(workspace: string, sessionId: string): string | null {
500
+ void workspace; void sessionId;
501
+ // Hermes ≥ 0.14 persists all chat to ~/.hermes/state.db (SQLite). The
502
+ // db file is the "path" we hand to the reader — it pulls the newest
503
+ // source='cli' session inside readSession.
504
+ const dbPath = path.join(os.homedir(), '.hermes', 'state.db');
505
+ if (fs.existsSync(dbPath)) return dbPath;
506
+ // Legacy fallback: pre-db hermes wrote per-session JSON dumps.
507
+ const dir = path.join(os.homedir(), '.hermes', 'sessions');
508
+ if (!fs.existsSync(dir)) return null;
509
+ return newestRecentFile(dir, /^session_.*\.json$/);
510
+ }
511
+
512
+ // ────────────────────────────────────────────────────────────────────────────
513
+ // Reader dispatch
514
+ // ────────────────────────────────────────────────────────────────────────────
515
+
516
+ function readByReader(
517
+ reader: ReaderId,
518
+ sourcePath: string,
519
+ sessionId: string,
520
+ workspace: string,
521
+ requestedProviderSid: string,
522
+ ): any | null {
523
+ switch (reader) {
524
+ case 'claude-cli': return readClaudeCliSession(sourcePath);
525
+ case 'codex-cli': return readCodexCliSession(sourcePath);
526
+ case 'antigravity-cli': return readAntigravityCliSession(sourcePath, sessionId || undefined, workspace || undefined);
527
+ // hermes reads a *shared* state.db and would otherwise pick the newest
528
+ // source='cli' session, which drifts every read (hermes ≥0.14 writes a
529
+ // fresh row per internal sub-session). Pass the bound id so it reads
530
+ // THAT session directly instead of newest-wins. claude/codex resolve a
531
+ // per-session file upstream, so they need no equivalent pin here.
532
+ case 'hermes-cli': return readHermesCliSession(sourcePath, requestedProviderSid || undefined);
533
+ }
534
+ }
535
+
536
+ // ────────────────────────────────────────────────────────────────────────────
537
+ // Helpers
538
+ // ────────────────────────────────────────────────────────────────────────────
539
+
540
+ function cwdAsDashes(cwd: string): string {
541
+ if (!cwd) return '';
542
+ return cwd.replace(/\//g, '-');
543
+ }
544
+
545
+ function codexSessionsRoot(): string {
546
+ return path.join(os.homedir(), '.codex', 'sessions');
547
+ }
548
+
549
+ function isUuidLikeSessionId(sessionId: string): boolean {
550
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
551
+ }
552
+
553
+ function isSafeFilename(name: string): boolean {
554
+ return /^[A-Za-z0-9._:-]+$/.test(name) && !name.includes('..');
555
+ }
556
+
557
+ function newestFile(dir: string, pattern: RegExp): string | null {
558
+ try {
559
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
560
+ .filter(e => e.isFile() && pattern.test(e.name))
561
+ .map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
562
+ .sort((a, b) => b.mtime - a.mtime);
563
+ return entries[0]?.p ?? null;
564
+ } catch { return null; }
565
+ }
566
+
567
+ /**
568
+ * Like newestFile but only returns a candidate when its mtime is within
569
+ * the recent activity window. Prevents the dashboard from surfacing a
570
+ * prior session's transcript when the daemon's sessionId doesn't match
571
+ * any file on disk (e.g. claude allocates its own uuid; daemon and
572
+ * agent disagree about what the "current" session is).
573
+ */
574
+ const RECENT_WINDOW_MS = 5 * 60 * 1000;
575
+ function newestRecentFile(dir: string, pattern: RegExp): string | null {
576
+ try {
577
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
578
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
579
+ .filter(e => e.isFile() && pattern.test(e.name))
580
+ .map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
581
+ .filter(e => e.mtime >= cutoff)
582
+ .sort((a, b) => b.mtime - a.mtime);
583
+ return entries[0]?.p ?? null;
584
+ } catch { return null; }
585
+ }
586
+
587
+ function safeMtime(p: string): number {
588
+ try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
589
+ }
590
+
591
+ /**
592
+ * File creation time in ms. birthtimeMs is high-precision on all shipped
593
+ * runners (NTFS/ext4/APFS), and a conversation .db is created by the CLI child
594
+ * strictly AFTER the daemon spawned it, so birthtime > the session's spawn
595
+ * floor for its own store. Falls back to mtime when birthtime is unavailable
596
+ * (0 / not tracked) so the caller still has a usable ordering key.
597
+ */
598
+ function safeBirthtime(p: string): number {
599
+ try {
600
+ const st = fs.statSync(p);
601
+ const birth = Math.floor(st.birthtimeMs);
602
+ return birth > 0 ? birth : Math.floor(st.mtimeMs);
603
+ } catch { return 0; }
604
+ }
605
+
606
+ function safeSize(p: string): number {
607
+ try { return fs.statSync(p).size; } catch { return 0; }
608
+ }
609
+
610
+ function normalizeRole(r: any): 'user' | 'assistant' | 'system' {
611
+ const s = String(r ?? '').toLowerCase();
612
+ if (s === 'user' || s === 'human') return 'user';
613
+ if (s === 'assistant' || s === 'ai' || s === 'model') return 'assistant';
614
+ // daemon's chat schema rejects 'tool'/'function' — surface as assistant.
615
+ if (s === 'tool' || s === 'tool_result' || s === 'function') return 'assistant';
616
+ return 'system';
617
+ }