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

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 (440) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +9 -0
  2. package/dist/boot/process-hardening.d.ts +50 -0
  3. package/dist/build-info.d.ts +37 -0
  4. package/dist/chat/source-machine.d.ts +166 -0
  5. package/dist/chat/source-resolver.d.ts +104 -0
  6. package/dist/chat/subscription-updates.d.ts +1 -0
  7. package/dist/cli-adapter-types.d.ts +68 -2
  8. package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
  9. package/dist/cli-adapters/cli-state-engine.d.ts +200 -0
  10. package/dist/cli-adapters/provider-cli-adapter.d.ts +126 -64
  11. package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
  12. package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
  13. package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
  14. package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
  15. package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
  16. package/dist/cli-adapters/resolve-executable.d.ts +69 -0
  17. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
  18. package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
  19. package/dist/cli-adapters/terminal-screen.d.ts +4 -11
  20. package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
  21. package/dist/commands/chat-commands-read.d.ts +7 -0
  22. package/dist/commands/chat-commands-scope.d.ts +39 -0
  23. package/dist/commands/chat-commands-shared.d.ts +33 -0
  24. package/dist/commands/chat-commands-write.d.ts +14 -0
  25. package/dist/commands/chat-commands.d.ts +10 -23
  26. package/dist/commands/cli-manager.d.ts +25 -1
  27. package/dist/commands/handler.d.ts +125 -0
  28. package/dist/commands/high-family/index.d.ts +3 -0
  29. package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
  30. package/dist/commands/high-family/mesh-events.d.ts +2 -0
  31. package/dist/commands/high-family/mesh-status.d.ts +2 -0
  32. package/dist/commands/high-family/types.d.ts +64 -0
  33. package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
  34. package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
  35. package/dist/commands/low-family/diagnostics.d.ts +2 -0
  36. package/dist/commands/low-family/index.d.ts +3 -0
  37. package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
  38. package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
  39. package/dist/commands/low-family/notification.d.ts +2 -0
  40. package/dist/commands/low-family/refine-config.d.ts +2 -0
  41. package/dist/commands/low-family/session-host.d.ts +2 -0
  42. package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
  43. package/dist/commands/low-family/status-meta.d.ts +2 -0
  44. package/dist/commands/low-family/types.d.ts +33 -0
  45. package/dist/commands/med-family/cli-agent.d.ts +2 -0
  46. package/dist/commands/med-family/fast-forward.d.ts +2 -0
  47. package/dist/commands/med-family/ide.d.ts +10 -0
  48. package/dist/commands/med-family/index.d.ts +3 -0
  49. package/dist/commands/med-family/mesh-crud.d.ts +48 -0
  50. package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
  51. package/dist/commands/med-family/mesh-queue.d.ts +2 -0
  52. package/dist/commands/med-family/mesh-restart.d.ts +2 -0
  53. package/dist/commands/med-family/types.d.ts +152 -0
  54. package/dist/commands/mesh-coordinator.d.ts +85 -1
  55. package/dist/commands/router-refine.d.ts +137 -0
  56. package/dist/commands/router-worktree-cleanup.d.ts +133 -0
  57. package/dist/commands/router.d.ts +241 -12
  58. package/dist/commands/upgrade-helper.d.ts +41 -1
  59. package/dist/config/chat-history.d.ts +9 -0
  60. package/dist/config/config.d.ts +19 -0
  61. package/dist/config/mesh-config.d.ts +136 -1
  62. package/dist/config/mesh-json-config.d.ts +199 -0
  63. package/dist/config/registry-resolver.d.ts +54 -0
  64. package/dist/config/repo-settings.d.ts +77 -0
  65. package/dist/daemon/dev-server.d.ts +0 -2
  66. package/dist/detection/cli-detector.d.ts +17 -0
  67. package/dist/detection/ide-detector.d.ts +13 -0
  68. package/dist/detection/win32-ide-version.d.ts +37 -0
  69. package/dist/git/change-impact-config.d.ts +159 -0
  70. package/dist/git/git-commands.d.ts +26 -2
  71. package/dist/git/git-diff.d.ts +6 -0
  72. package/dist/git/git-executor.d.ts +11 -0
  73. package/dist/git/git-status.d.ts +57 -0
  74. package/dist/git/git-types.d.ts +2 -50
  75. package/dist/git/git-worktree.d.ts +71 -1
  76. package/dist/git/index.d.ts +3 -1
  77. package/dist/index.d.ts +67 -15
  78. package/dist/index.js +58583 -25541
  79. package/dist/index.js.map +1 -1
  80. package/dist/index.mjs +58207 -25332
  81. package/dist/index.mjs.map +1 -1
  82. package/dist/installer.d.ts +1 -4
  83. package/dist/ipc/local-ipc-server.d.ts +91 -0
  84. package/dist/launch.d.ts +1 -1
  85. package/dist/logging/async-batch-writer.d.ts +10 -0
  86. package/dist/logging/debug-config.d.ts +16 -0
  87. package/dist/logging/log-redactor.d.ts +24 -0
  88. package/dist/logging/log-tail-reader.d.ts +81 -0
  89. package/dist/logging/logger.d.ts +1 -1
  90. package/dist/mesh/contracts.d.ts +230 -0
  91. package/dist/mesh/coordinator-prompt.d.ts +76 -0
  92. package/dist/mesh/coordinator-registry.d.ts +59 -0
  93. package/dist/mesh/mesh-active-work.d.ts +174 -0
  94. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  95. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  96. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  97. package/dist/mesh/mesh-event-classify.d.ts +7 -0
  98. package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
  99. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  100. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  101. package/dist/mesh/mesh-events-pending.d.ts +155 -0
  102. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  103. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  104. package/dist/mesh/mesh-events.d.ts +6 -49
  105. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  106. package/dist/mesh/mesh-host-ownership.d.ts +29 -0
  107. package/dist/mesh/mesh-init.d.ts +128 -0
  108. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  109. package/dist/mesh/mesh-ledger.d.ts +133 -1
  110. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  111. package/dist/mesh/mesh-missions.d.ts +189 -0
  112. package/dist/mesh/mesh-node-identity.d.ts +310 -0
  113. package/dist/mesh/mesh-queue-assignment.d.ts +158 -0
  114. package/dist/mesh/mesh-reconcile-loop.d.ts +80 -0
  115. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  116. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  117. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  118. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  119. package/dist/mesh/mesh-routing.d.ts +70 -0
  120. package/dist/mesh/mesh-runtime-store.d.ts +493 -0
  121. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  122. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  123. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  124. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  125. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  126. package/dist/mesh/mesh-work-queue.d.ts +318 -5
  127. package/dist/mesh/preview-freshness.d.ts +28 -0
  128. package/dist/mesh/refine-config.d.ts +216 -0
  129. package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
  130. package/dist/providers/acp-provider-instance.d.ts +5 -0
  131. package/dist/providers/approval-utils.d.ts +45 -0
  132. package/dist/providers/chat-message-normalization.d.ts +58 -1
  133. package/dist/providers/cli-provider-instance.d.ts +290 -3
  134. package/dist/providers/contracts.d.ts +149 -6
  135. package/dist/providers/external-sources.d.ts +71 -0
  136. package/dist/providers/manual-attendance.d.ts +79 -0
  137. package/dist/providers/native-history/antigravity-claim-registry.d.ts +28 -0
  138. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -0
  139. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  140. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  141. package/dist/providers/native-history/constants.d.ts +12 -0
  142. package/dist/providers/native-history/dispatcher.d.ts +31 -0
  143. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  144. package/dist/providers/native-history/index.d.ts +13 -0
  145. package/dist/providers/provider-instance-manager.d.ts +29 -0
  146. package/dist/providers/provider-instance.d.ts +30 -1
  147. package/dist/providers/provider-loader.d.ts +42 -5
  148. package/dist/providers/provider-trust.d.ts +31 -0
  149. package/dist/providers/read-chat-contract.d.ts +29 -0
  150. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  151. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  152. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  153. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  154. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  155. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  156. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  157. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  158. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  159. package/dist/providers/sdk/v1/index.d.ts +30 -0
  160. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  161. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  162. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  163. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  164. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  165. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  166. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  167. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  168. package/dist/providers/spec/adapter.d.ts +98 -0
  169. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  170. package/dist/providers/spec/evaluator.d.ts +45 -0
  171. package/dist/providers/spec/fsm-driver.d.ts +449 -0
  172. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  173. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  174. package/dist/providers/spec/fsm-types.d.ts +202 -0
  175. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  176. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  177. package/dist/providers/spec/route.d.ts +4 -0
  178. package/dist/providers/spec/types.d.ts +222 -0
  179. package/dist/providers/status-monitor.d.ts +7 -7
  180. package/dist/providers/transcript-v2.d.ts +176 -0
  181. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  182. package/dist/providers/working-dir.d.ts +17 -0
  183. package/dist/repo-mesh-types.d.ts +598 -12
  184. package/dist/runtime-defaults.d.ts +2 -0
  185. package/dist/session-host/managed-host.d.ts +64 -0
  186. package/dist/session-host/runtime-surface.d.ts +10 -16
  187. package/dist/sessions/registry.d.ts +6 -0
  188. package/dist/shared-types-extra.d.ts +2 -4
  189. package/dist/shared-types.d.ts +86 -55
  190. package/dist/status/normalize.d.ts +1 -1
  191. package/dist/status/normalize.js +1 -0
  192. package/dist/status/normalize.js.map +1 -1
  193. package/dist/status/normalize.mjs +1 -0
  194. package/dist/status/normalize.mjs.map +1 -1
  195. package/dist/status/reporter.d.ts +2 -0
  196. package/dist/status/snapshot.d.ts +26 -0
  197. package/dist/system/hash.d.ts +8 -0
  198. package/dist/system/load-better-sqlite3.d.ts +21 -0
  199. package/dist/types.d.ts +5 -0
  200. package/package.json +11 -4
  201. package/src/agent-stream/poller.ts +2 -3
  202. package/src/agent-stream/provider-adapter.ts +1 -1
  203. package/src/boot/daemon-lifecycle.ts +80 -14
  204. package/src/boot/process-hardening.ts +89 -0
  205. package/src/build-info.ts +73 -0
  206. package/src/chat/source-machine.ts +534 -0
  207. package/src/chat/source-resolver.ts +0 -0
  208. package/src/chat/subscription-updates.ts +20 -1
  209. package/src/cli-adapter-types.d.ts +3 -1
  210. package/src/cli-adapter-types.ts +68 -2
  211. package/src/cli-adapters/cli-script-runner.ts +421 -0
  212. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  213. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  214. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  215. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  216. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  217. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  218. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  219. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  220. package/src/cli-adapters/pty-transport.ts +2 -1
  221. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  222. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  223. package/src/cli-adapters/resolve-executable.ts +204 -0
  224. package/src/cli-adapters/session-host-transport.ts +2 -1
  225. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  226. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  227. package/src/cli-adapters/terminal-screen.ts +16 -81
  228. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  229. package/src/commands/chat-commands-read.ts +2488 -0
  230. package/src/commands/chat-commands-scope.ts +54 -0
  231. package/src/commands/chat-commands-shared.ts +114 -0
  232. package/src/commands/chat-commands-write.ts +891 -0
  233. package/src/commands/chat-commands.ts +19 -1841
  234. package/src/commands/cli-manager.ts +596 -27
  235. package/src/commands/handler.ts +845 -2
  236. package/src/commands/high-family/index.ts +28 -0
  237. package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
  238. package/src/commands/high-family/mesh-events.ts +89 -0
  239. package/src/commands/high-family/mesh-status.ts +832 -0
  240. package/src/commands/high-family/types.ts +80 -0
  241. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  242. package/src/commands/low-family/daemon-lifecycle.ts +120 -0
  243. package/src/commands/low-family/diagnostics.ts +57 -0
  244. package/src/commands/low-family/index.ts +37 -0
  245. package/src/commands/low-family/mesh-ledger.ts +62 -0
  246. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  247. package/src/commands/low-family/notification.ts +116 -0
  248. package/src/commands/low-family/refine-config.ts +106 -0
  249. package/src/commands/low-family/session-host.ts +274 -0
  250. package/src/commands/low-family/spec-providerdev.ts +217 -0
  251. package/src/commands/low-family/status-meta.ts +112 -0
  252. package/src/commands/low-family/types.ts +39 -0
  253. package/src/commands/med-family/cli-agent.ts +241 -0
  254. package/src/commands/med-family/fast-forward.ts +230 -0
  255. package/src/commands/med-family/ide.ts +163 -0
  256. package/src/commands/med-family/index.ts +37 -0
  257. package/src/commands/med-family/mesh-crud.ts +1287 -0
  258. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  259. package/src/commands/med-family/mesh-queue.ts +167 -0
  260. package/src/commands/med-family/mesh-restart.ts +92 -0
  261. package/src/commands/med-family/types.ts +153 -0
  262. package/src/commands/mesh-coordinator.ts +334 -124
  263. package/src/commands/router-refine.ts +1711 -0
  264. package/src/commands/router-worktree-cleanup.ts +870 -0
  265. package/src/commands/router.ts +1025 -4070
  266. package/src/commands/stream-commands.ts +8 -0
  267. package/src/commands/upgrade-helper.ts +310 -45
  268. package/src/config/chat-history.ts +493 -24
  269. package/src/config/config.ts +30 -0
  270. package/src/config/mesh-config.ts +632 -23
  271. package/src/config/mesh-json-config.ts +376 -0
  272. package/src/config/recent-activity.ts +8 -2
  273. package/src/config/registry-resolver.ts +100 -0
  274. package/src/config/repo-settings.ts +111 -0
  275. package/src/daemon/dev-auto-implement.ts +3 -2
  276. package/src/daemon/dev-cli-debug.ts +10 -1
  277. package/src/daemon/dev-server.ts +0 -541
  278. package/src/detection/cli-detector.ts +94 -9
  279. package/src/detection/ide-detector.ts +55 -16
  280. package/src/detection/win32-ide-version.ts +106 -0
  281. package/src/git/change-impact-config.ts +354 -0
  282. package/src/git/git-commands.ts +112 -16
  283. package/src/git/git-diff.ts +81 -11
  284. package/src/git/git-executor.ts +12 -0
  285. package/src/git/git-status.ts +767 -48
  286. package/src/git/git-types.ts +14 -62
  287. package/src/git/git-worktree.ts +261 -4
  288. package/src/git/index.ts +17 -0
  289. package/src/index.ts +200 -12
  290. package/src/installer.d.ts +1 -1
  291. package/src/installer.ts +8 -6
  292. package/src/ipc/local-ipc-server.ts +278 -0
  293. package/src/launch.d.ts +1 -1
  294. package/src/launch.ts +37 -28
  295. package/src/logging/async-batch-writer.ts +55 -0
  296. package/src/logging/command-log.ts +7 -5
  297. package/src/logging/debug-config.ts +25 -0
  298. package/src/logging/debug-trace.ts +7 -2
  299. package/src/logging/log-redactor.ts +100 -0
  300. package/src/logging/log-tail-reader.ts +341 -0
  301. package/src/logging/logger.ts +14 -7
  302. package/src/mesh/contracts.ts +469 -0
  303. package/src/mesh/coordinator-prompt.ts +554 -34
  304. package/src/mesh/coordinator-registry.ts +121 -0
  305. package/src/mesh/mesh-active-work.ts +656 -0
  306. package/src/mesh/mesh-clone-grace.ts +68 -0
  307. package/src/mesh/mesh-coordinator-config.ts +97 -0
  308. package/src/mesh/mesh-delivery-policy.ts +315 -0
  309. package/src/mesh/mesh-event-classify.ts +73 -0
  310. package/src/mesh/mesh-event-forwarding.ts +1950 -0
  311. package/src/mesh/mesh-event-trace.ts +67 -0
  312. package/src/mesh/mesh-events-coordinator.ts +32 -0
  313. package/src/mesh/mesh-events-pending.ts +1132 -0
  314. package/src/mesh/mesh-events-stale.ts +440 -0
  315. package/src/mesh/mesh-events-utils.ts +443 -0
  316. package/src/mesh/mesh-events.ts +35 -1035
  317. package/src/mesh/mesh-fast-forward.ts +856 -0
  318. package/src/mesh/mesh-host-ownership.ts +111 -0
  319. package/src/mesh/mesh-init.ts +350 -0
  320. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  321. package/src/mesh/mesh-ledger.ts +873 -102
  322. package/src/mesh/mesh-magi-status.ts +223 -0
  323. package/src/mesh/mesh-missions.ts +449 -0
  324. package/src/mesh/mesh-node-identity.ts +2065 -0
  325. package/src/mesh/mesh-queue-assignment.ts +2233 -0
  326. package/src/mesh/mesh-reconcile-loop.ts +2397 -0
  327. package/src/mesh/mesh-refine-batch.ts +205 -0
  328. package/src/mesh/mesh-refine-gates.ts +1686 -0
  329. package/src/mesh/mesh-refine-status.ts +231 -0
  330. package/src/mesh/mesh-review-inbox.ts +308 -0
  331. package/src/mesh/mesh-routing.ts +291 -0
  332. package/src/mesh/mesh-runtime-store.ts +2056 -0
  333. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  334. package/src/mesh/mesh-task-inflight.ts +70 -0
  335. package/src/mesh/mesh-task-stats.ts +161 -0
  336. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  337. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  338. package/src/mesh/mesh-work-queue.ts +1281 -141
  339. package/src/mesh/preview-freshness.ts +163 -0
  340. package/src/mesh/refine-config.ts +423 -0
  341. package/src/mesh/worktree-bootstrap-config.ts +599 -0
  342. package/src/providers/acp-provider-instance.ts +43 -10
  343. package/src/providers/approval-utils.d.ts +5 -0
  344. package/src/providers/approval-utils.ts +99 -5
  345. package/src/providers/chat-message-normalization.ts +126 -4
  346. package/src/providers/cli-provider-instance.ts +2456 -107
  347. package/src/providers/contracts.d.ts +55 -0
  348. package/src/providers/contracts.ts +160 -6
  349. package/src/providers/extension-provider-instance.ts +12 -7
  350. package/src/providers/external-sources.ts +218 -0
  351. package/src/providers/ide-provider-instance.ts +35 -12
  352. package/src/providers/manual-attendance.ts +105 -0
  353. package/src/providers/native-history/antigravity-claim-registry.ts +131 -0
  354. package/src/providers/native-history/antigravity-cli-transcript.ts +1193 -0
  355. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  356. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  357. package/src/providers/native-history/constants.ts +19 -0
  358. package/src/providers/native-history/dispatcher.ts +503 -0
  359. package/src/providers/native-history/hermes-cli-transcript.ts +260 -0
  360. package/src/providers/native-history/index.ts +30 -0
  361. package/src/providers/provider-instance-manager.ts +71 -0
  362. package/src/providers/provider-instance.ts +24 -1
  363. package/src/providers/provider-loader.ts +700 -55
  364. package/src/providers/provider-schema.ts +87 -14
  365. package/src/providers/provider-trust.ts +114 -0
  366. package/src/providers/read-chat-contract.ts +76 -16
  367. package/src/providers/sdk/README.md +49 -0
  368. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  369. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  370. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  371. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
  372. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  373. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  374. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  375. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  376. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  377. package/src/providers/sdk/v1/index.ts +152 -0
  378. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  379. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  380. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  381. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +509 -0
  382. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  383. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  384. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  385. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  386. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  387. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  388. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  389. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  390. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  391. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  392. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  393. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  394. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  395. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  396. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  397. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  398. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  399. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  400. package/src/providers/sdk/v1/validators/index.ts +19 -0
  401. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  402. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  403. package/src/providers/spec/adapter.ts +246 -0
  404. package/src/providers/spec/cli-adapter.ts +1064 -0
  405. package/src/providers/spec/evaluator.ts +407 -0
  406. package/src/providers/spec/fsm-driver.ts +1528 -0
  407. package/src/providers/spec/fsm-evaluator.ts +290 -0
  408. package/src/providers/spec/fsm-loader.ts +128 -0
  409. package/src/providers/spec/fsm-types.ts +301 -0
  410. package/src/providers/spec/native-history-executor.ts +1174 -0
  411. package/src/providers/spec/pre-launch-trust.ts +104 -0
  412. package/src/providers/spec/route.ts +51 -0
  413. package/src/providers/spec/types.ts +262 -0
  414. package/src/providers/status-monitor.d.ts +7 -7
  415. package/src/providers/status-monitor.ts +37 -22
  416. package/src/providers/transcript-v2.ts +567 -0
  417. package/src/providers/types/interactive-prompt.ts +536 -0
  418. package/src/providers/version-archive.ts +64 -24
  419. package/src/providers/working-dir.ts +23 -0
  420. package/src/repo-mesh-types.ts +836 -13
  421. package/src/runtime-defaults.ts +39 -0
  422. package/src/session-host/managed-host.ts +218 -0
  423. package/src/session-host/runtime-surface.ts +20 -80
  424. package/src/sessions/registry.ts +6 -0
  425. package/src/shared-types-extra.ts +2 -4
  426. package/src/shared-types.d.ts +8 -0
  427. package/src/shared-types.ts +124 -55
  428. package/src/status/builders.ts +26 -6
  429. package/src/status/normalize.ts +2 -0
  430. package/src/status/reporter.ts +19 -1
  431. package/src/status/snapshot.ts +95 -26
  432. package/src/system/hash.ts +23 -0
  433. package/src/system/host-memory.ts +29 -12
  434. package/src/system/load-better-sqlite3.ts +68 -0
  435. package/src/types.ts +5 -0
  436. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  437. package/dist/mesh/mesh-sync.d.ts +0 -53
  438. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  439. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  440. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,503 @@
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
+
55
+ export function createNativeHistoryDispatcher(reader: ReaderId): (input: NativeHistoryInput) => NativeHistoryResult | null {
56
+ return (input: NativeHistoryInput) => {
57
+ const workspace = input.workspace || '';
58
+ const sessionId = input.sessionId || input.historySessionId || '';
59
+ // Caller may pass a providerSessionId (the *provider's own* id, e.g.
60
+ // the uuid claude writes into the jsonl basename). When present, the
61
+ // dispatcher only returns a transcript whose file id matches —
62
+ // otherwise the newest_by_mtime fallback can surface a different
63
+ // session's chat (round 9 part b: the user reported "previous chat
64
+ // shows up before I type anything" on every provider).
65
+ const requestedProviderSid = input.providerSessionId || '';
66
+
67
+ const sessionStartedAtMs = typeof input.sessionStartedAtMs === 'number'
68
+ ? input.sessionStartedAtMs
69
+ : typeof input.args?.sessionStartedAtMs === 'number'
70
+ ? input.args.sessionStartedAtMs
71
+ : 0;
72
+ const instanceId = typeof input.instanceId === 'string'
73
+ ? input.instanceId
74
+ : typeof input.args?.instanceId === 'string'
75
+ ? (input.args.instanceId as string)
76
+ : '';
77
+ const sourcePath = resolveSourcePath(reader, workspace, sessionId, sessionStartedAtMs, instanceId);
78
+ if (!sourcePath) return null;
79
+ if (input.forceRefresh === true || input.args?.forceRefresh === true) {
80
+ try { fs.statSync(sourcePath); } catch { /* best-effort metadata refresh */ }
81
+ }
82
+
83
+ const session = readByReader(reader, sourcePath, sessionId, workspace, requestedProviderSid);
84
+ if (!session) return null;
85
+
86
+ if (requestedProviderSid && session.providerSessionId && session.providerSessionId !== requestedProviderSid) {
87
+ return null;
88
+ }
89
+
90
+ return {
91
+ messages: session.messages.map((m: any) => ({
92
+ role: normalizeRole(m.role),
93
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
94
+ receivedAt: typeof m.receivedAt === 'number' ? m.receivedAt : Date.parse(m.timestamp || '') || Date.now(),
95
+ kind: typeof m.kind === 'string' ? m.kind : 'standard',
96
+ workspace: typeof m.workspace === 'string' ? m.workspace : workspace || undefined,
97
+ })),
98
+ providerSessionId: session.providerSessionId,
99
+ sourcePath: session.sourcePath,
100
+ sourceMtimeMs: session.sourceMtimeMs,
101
+ nativeHistoryCoverage: (session as any).nativeHistoryCoverage || 'full',
102
+ };
103
+ };
104
+ }
105
+
106
+ // ────────────────────────────────────────────────────────────────────────────
107
+ // Per-provider path resolution
108
+ // ────────────────────────────────────────────────────────────────────────────
109
+
110
+ function resolveSourcePath(reader: ReaderId, workspace: string, sessionId: string, sessionStartedAtMs: number, instanceId: string): string | null {
111
+ switch (reader) {
112
+ case 'claude-cli': return resolveClaudePath(workspace, sessionId);
113
+ case 'codex-cli': return resolveCodexPath(workspace, sessionId, sessionStartedAtMs);
114
+ case 'antigravity-cli': return resolveAntigravityPath(workspace, sessionId, sessionStartedAtMs, instanceId);
115
+ case 'hermes-cli': return resolveHermesPath(workspace, sessionId);
116
+ }
117
+ }
118
+
119
+ function resolveClaudePath(workspace: string, sessionId: string): string | null {
120
+ // claude stores per-cwd: ~/.claude/projects/<cwd-as-dashes>/<uuid>.jsonl
121
+ const dir = path.join(os.homedir(), '.claude', 'projects', cwdAsDashes(workspace));
122
+ if (!fs.existsSync(dir)) return null;
123
+ if (sessionId) {
124
+ const candidate = path.join(dir, `${sessionId}.jsonl`);
125
+ if (fs.existsSync(candidate)) return candidate;
126
+ }
127
+ // No exact match: return null. The newest_by_mtime fallback used to
128
+ // grab whichever transcript was touched most recently, but that
129
+ // surfaced a different (often the user's *external* claude session
130
+ // in the same workspace) chat in the dashboard before the user
131
+ // typed anything. The right answer is to show nothing until either
132
+ // the daemon's sessionId actually maps to a file or the caller
133
+ // passes the correct providerSessionId (round 9 part b).
134
+ return null;
135
+ }
136
+
137
+ function resolveCodexPath(workspace: string, sessionId: string, sessionStartedAtMs: number): string | null {
138
+ // codex stores by UTC date: ~/.codex/sessions/<year>/<month>/<day>/<file>.jsonl
139
+ const root = codexSessionsRoot();
140
+ if (sessionId && isUuidLikeSessionId(sessionId)) {
141
+ return findCodexPathBySessionId(root, sessionId);
142
+ }
143
+ return findCodexPathByRuntime(root, workspace, sessionStartedAtMs);
144
+ }
145
+
146
+ function findCodexPathBySessionId(root: string, sessionId: string): string | null {
147
+ if (!fs.existsSync(root)) return null;
148
+ const needle = sessionId.toLowerCase();
149
+ const matches: Array<{ p: string; mtime: number }> = [];
150
+ const stack: string[] = [root];
151
+ while (stack.length > 0) {
152
+ const current = stack.pop()!;
153
+ let entries: fs.Dirent[] = [];
154
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
155
+ for (const entry of entries) {
156
+ const entryPath = path.join(current, entry.name);
157
+ if (entry.isDirectory()) {
158
+ stack.push(entryPath);
159
+ continue;
160
+ }
161
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
162
+ if (!entry.name.toLowerCase().includes(needle)) continue;
163
+ if (!isSafeFilename(entry.name.replace('.jsonl', ''))) continue;
164
+ matches.push({ p: entryPath, mtime: safeMtime(entryPath) });
165
+ }
166
+ }
167
+ matches.sort((a, b) => b.mtime - a.mtime);
168
+ return matches[0]?.p ?? null;
169
+ }
170
+
171
+ function findCodexPathByRuntime(root: string, workspace: string, sessionStartedAtMs: number): string | null {
172
+ if (!fs.existsSync(root) || !workspace) return null;
173
+ const workspaceResolved = resolveRealPath(workspace);
174
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
175
+ const matches: Array<{ p: string; mtime: number; diff: number }> = [];
176
+ const stack: string[] = [root];
177
+
178
+ while (stack.length > 0) {
179
+ const current = stack.pop()!;
180
+ let entries: fs.Dirent[] = [];
181
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
182
+ for (const entry of entries) {
183
+ const entryPath = path.join(current, entry.name);
184
+ if (entry.isDirectory()) {
185
+ stack.push(entryPath);
186
+ continue;
187
+ }
188
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
189
+ const mtime = safeMtime(entryPath);
190
+ if (mtime < cutoff) continue;
191
+ const meta = readCodexSessionMeta(entryPath);
192
+ if (!meta?.cwd || resolveRealPath(meta.cwd) !== workspaceResolved) continue;
193
+ const diff = sessionStartedAtMs > 0 && meta.timestampMs != null
194
+ ? Math.abs(meta.timestampMs - sessionStartedAtMs)
195
+ : 0;
196
+ if (sessionStartedAtMs > 0 && (meta.timestampMs == null || diff > SPAWN_BIND_GRACE_MS)) continue;
197
+ matches.push({ p: entryPath, mtime, diff });
198
+ }
199
+ }
200
+
201
+ matches.sort((a, b) => sessionStartedAtMs > 0
202
+ ? a.diff - b.diff || b.mtime - a.mtime
203
+ : b.mtime - a.mtime);
204
+ return matches[0]?.p ?? null;
205
+ }
206
+
207
+ function readCodexSessionMeta(filePath: string): { cwd?: string; timestampMs?: number } | null {
208
+ try {
209
+ const fd = fs.openSync(filePath, 'r');
210
+ try {
211
+ const buffer = Buffer.alloc(8192);
212
+ const bytes = fs.readSync(fd, buffer, 0, buffer.length, 0);
213
+ if (bytes <= 0) return null;
214
+ const text = buffer.subarray(0, bytes).toString('utf8');
215
+ const firstLine = text.slice(0, text.indexOf('\n') >= 0 ? text.indexOf('\n') : text.length).trim();
216
+ if (!firstLine) return null;
217
+ const record = JSON.parse(firstLine) as Record<string, unknown>;
218
+ if (record.type !== 'session_meta' || !record.payload || typeof record.payload !== 'object') return null;
219
+ const payload = record.payload as Record<string, unknown>;
220
+ const timestampRaw = payload.timestamp;
221
+ const timestampMs = typeof timestampRaw === 'string'
222
+ ? Date.parse(timestampRaw)
223
+ : typeof timestampRaw === 'number'
224
+ ? (timestampRaw < 1e12 ? timestampRaw * 1000 : timestampRaw)
225
+ : NaN;
226
+ return {
227
+ cwd: typeof payload.cwd === 'string' ? payload.cwd : undefined,
228
+ timestampMs: Number.isFinite(timestampMs) ? timestampMs : undefined,
229
+ };
230
+ } finally {
231
+ fs.closeSync(fd);
232
+ }
233
+ } catch {
234
+ return null;
235
+ }
236
+ }
237
+
238
+ function resolveRealPath(value: string): string {
239
+ try { return fs.realpathSync(value); } catch { return value; }
240
+ }
241
+
242
+ /**
243
+ * The daemon may stamp a session's spawn time a hair before the CLI child
244
+ * actually creates its conversation .db, so treat a store born within this
245
+ * grace of the spawn floor as still belonging to this session. Kept small
246
+ * (< a typical concurrent-spawn gap) so a sibling's PRE-spawn store is still
247
+ * excluded rather than mis-bound.
248
+ */
249
+ const AGY_SPAWN_CLAIM_GRACE_MS = 2000;
250
+
251
+ function resolveAntigravityPath(
252
+ workspace: string,
253
+ sessionId: string,
254
+ sessionStartedAtMs: number,
255
+ instanceId: string,
256
+ ): string | null {
257
+ const agyRoot = path.join(os.homedir(), '.gemini', 'antigravity-cli');
258
+ // Owner token identifies THIS reading session. The provider instance derives
259
+ // the identical token (workspace + startedAt, or instanceId) so it can
260
+ // release these claims on shutdown. '' when there is no stable identity to
261
+ // key on — claiming is then skipped but exclusion still runs.
262
+ const owner = antigravityOwnerToken(workspace, sessionStartedAtMs, instanceId);
263
+
264
+ // (1) Exact session bind + LOCK: current antigravity writes a per-session
265
+ // SQLite db at conversations/<uuid>.db. Once the caller knows the session
266
+ // id, bind straight to it — this is authoritative and never re-resolves
267
+ // by mtime, so an already-bound session cannot be hijacked by a newer
268
+ // .db on a later read. Claim it so a concurrent unbound sibling can never
269
+ // grab this same conversation.
270
+ if (sessionId && isUuidLikeSessionId(sessionId)) {
271
+ const dbPath = path.join(agyRoot, 'conversations', `${sessionId}.db`);
272
+ if (fs.existsSync(dbPath)) {
273
+ if (owner) claimAntigravityConversation(sessionId, owner);
274
+ return dbPath;
275
+ }
276
+ }
277
+
278
+ // (2) brain/<uuid>/.system_generated/logs/transcript.jsonl (legacy full source).
279
+ // Only bind to a brain transcript that is NON-EMPTY: current antigravity
280
+ // writes this file but leaves it 0 bytes (all real conversation data now
281
+ // lives in the per-session .db), so an empty transcript here would
282
+ // otherwise shadow the .db fallback below and return no messages. Skip
283
+ // empty transcripts so an unbound read still reaches the .db. Exclude any
284
+ // brain conversation already claimed by a DIFFERENT live session.
285
+ const brainRoot = path.join(agyRoot, 'brain');
286
+ if (fs.existsSync(brainRoot)) {
287
+ const cutoff = spawnAwareCutoff(sessionStartedAtMs);
288
+ const entries = fs.readdirSync(brainRoot, { withFileTypes: true })
289
+ .filter(e => e.isDirectory() && isUuidLikeSessionId(e.name))
290
+ .filter(e => !isAntigravityConversationClaimedByOther(e.name, owner))
291
+ .map(e => ({ uuid: e.name, p: path.join(brainRoot, e.name), mtime: safeMtime(path.join(brainRoot, e.name)) }))
292
+ .filter(e => e.mtime >= cutoff)
293
+ .sort((a, b) => b.mtime - a.mtime);
294
+ for (const e of entries) {
295
+ const t = path.join(e.p, '.system_generated', 'logs', 'transcript.jsonl');
296
+ if (fs.existsSync(t) && safeSize(t) > 0) {
297
+ if (owner) claimAntigravityConversation(e.uuid, owner);
298
+ return t;
299
+ }
300
+ }
301
+ }
302
+
303
+ // (3) No brain transcript and no bound session id: pick a conversations/<uuid>.db
304
+ // that is NOT claimed by another live session, guarded by this session's
305
+ // spawn time so we never mis-bind to a sibling's earlier store.
306
+ const convRoot = path.join(agyRoot, 'conversations');
307
+ const picked = pickUnboundConversationDb(convRoot, sessionStartedAtMs, owner);
308
+ if (picked) {
309
+ if (owner) claimAntigravityConversation(picked.uuid, owner);
310
+ return picked.path;
311
+ }
312
+
313
+ return null;
314
+ }
315
+
316
+ /**
317
+ * Choose the conversations/<uuid>.db for an as-yet-unbound antigravity session.
318
+ *
319
+ * Two isolation rules keep concurrent sessions apart:
320
+ * - claim exclusion: skip any .db already owned by a DIFFERENT live session,
321
+ * so two sessions can never resolve to the same conversation;
322
+ * - spawn-window guard: a session's own store is created at/after it spawned,
323
+ * so when a spawn floor is known, only stores born at/after (floor - grace)
324
+ * are eligible. A store that predates this session's spawn belongs to an
325
+ * earlier session and is never bound — if none qualifies we return null
326
+ * (native_history_empty) and let the caller retry once this session's own
327
+ * store appears, rather than binding a sibling's conversation.
328
+ *
329
+ * Among eligible unclaimed stores the OLDEST-created wins: in the normal case
330
+ * (each session polls native history only after its own store exists, and an
331
+ * earlier-spawned session polls earlier) this hands each session the first
332
+ * store created after it started — its own. When no spawn floor is available
333
+ * (legacy/unpinned discovery) we fall back to newest-by-mtime within the
334
+ * recency window, preserving the original single-session behaviour.
335
+ */
336
+ function pickUnboundConversationDb(
337
+ convRoot: string,
338
+ sessionFloorMs: number,
339
+ owner: string,
340
+ ): { path: string; uuid: string } | null {
341
+ let entries: fs.Dirent[] = [];
342
+ try { entries = fs.readdirSync(convRoot, { withFileTypes: true }); } catch { return null; }
343
+
344
+ const recencyCutoff = Date.now() - RECENT_WINDOW_MS;
345
+ const candidates: Array<{ path: string; uuid: string; mtime: number; birth: number }> = [];
346
+ for (const entry of entries) {
347
+ if (!entry.isFile()) continue;
348
+ const match = /^([0-9a-f-]+)\.db$/i.exec(entry.name);
349
+ if (!match || !isUuidLikeSessionId(match[1])) continue;
350
+ const uuid = match[1];
351
+ // (isolation) never consider a conversation a different live session owns.
352
+ if (isAntigravityConversationClaimedByOther(uuid, owner)) continue;
353
+ const p = path.join(convRoot, entry.name);
354
+ const mtime = safeMtime(p);
355
+ if (mtime < recencyCutoff) continue;
356
+ candidates.push({ path: p, uuid, mtime, birth: safeBirthtime(p) });
357
+ }
358
+ if (candidates.length === 0) return null;
359
+
360
+ if (sessionFloorMs > 0) {
361
+ const floor = sessionFloorMs - AGY_SPAWN_CLAIM_GRACE_MS;
362
+ const own = candidates.filter(c => (c.birth > 0 ? c.birth : c.mtime) >= floor);
363
+ // A store created before this session spawned belongs to an earlier
364
+ // session — do NOT bind to it. Wait for our own store on the next read.
365
+ if (own.length === 0) return null;
366
+ own.sort((a, b) => (a.birth || a.mtime) - (b.birth || b.mtime));
367
+ return { path: own[0].path, uuid: own[0].uuid };
368
+ }
369
+
370
+ candidates.sort((a, b) => b.mtime - a.mtime);
371
+ return { path: candidates[0].path, uuid: candidates[0].uuid };
372
+ }
373
+
374
+ /**
375
+ * mtime floor for the brain-transcript scan: the later of the recency window
376
+ * and this session's spawn floor (minus the claim grace), so a fresh read
377
+ * cannot surface a brain dir last touched before this session started.
378
+ */
379
+ function spawnAwareCutoff(sessionStartedAtMs: number): number {
380
+ const recency = Date.now() - RECENT_WINDOW_MS;
381
+ if (sessionStartedAtMs > 0) return Math.max(recency, sessionStartedAtMs - AGY_SPAWN_CLAIM_GRACE_MS);
382
+ return recency;
383
+ }
384
+
385
+ function resolveHermesPath(workspace: string, sessionId: string): string | null {
386
+ void workspace; void sessionId;
387
+ // Hermes ≥ 0.14 persists all chat to ~/.hermes/state.db (SQLite). The
388
+ // db file is the "path" we hand to the reader — it pulls the newest
389
+ // source='cli' session inside readSession.
390
+ const dbPath = path.join(os.homedir(), '.hermes', 'state.db');
391
+ if (fs.existsSync(dbPath)) return dbPath;
392
+ // Legacy fallback: pre-db hermes wrote per-session JSON dumps.
393
+ const dir = path.join(os.homedir(), '.hermes', 'sessions');
394
+ if (!fs.existsSync(dir)) return null;
395
+ return newestRecentFile(dir, /^session_.*\.json$/);
396
+ }
397
+
398
+ // ────────────────────────────────────────────────────────────────────────────
399
+ // Reader dispatch
400
+ // ────────────────────────────────────────────────────────────────────────────
401
+
402
+ function readByReader(
403
+ reader: ReaderId,
404
+ sourcePath: string,
405
+ sessionId: string,
406
+ workspace: string,
407
+ requestedProviderSid: string,
408
+ ): any | null {
409
+ switch (reader) {
410
+ case 'claude-cli': return readClaudeCliSession(sourcePath);
411
+ case 'codex-cli': return readCodexCliSession(sourcePath);
412
+ case 'antigravity-cli': return readAntigravityCliSession(sourcePath, sessionId || undefined, workspace || undefined);
413
+ // hermes reads a *shared* state.db and would otherwise pick the newest
414
+ // source='cli' session, which drifts every read (hermes ≥0.14 writes a
415
+ // fresh row per internal sub-session). Pass the bound id so it reads
416
+ // THAT session directly instead of newest-wins. claude/codex resolve a
417
+ // per-session file upstream, so they need no equivalent pin here.
418
+ case 'hermes-cli': return readHermesCliSession(sourcePath, requestedProviderSid || undefined);
419
+ }
420
+ }
421
+
422
+ // ────────────────────────────────────────────────────────────────────────────
423
+ // Helpers
424
+ // ────────────────────────────────────────────────────────────────────────────
425
+
426
+ function cwdAsDashes(cwd: string): string {
427
+ if (!cwd) return '';
428
+ return cwd.replace(/\//g, '-');
429
+ }
430
+
431
+ function codexSessionsRoot(): string {
432
+ return path.join(os.homedir(), '.codex', 'sessions');
433
+ }
434
+
435
+ function isUuidLikeSessionId(sessionId: string): boolean {
436
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
437
+ }
438
+
439
+ function isSafeFilename(name: string): boolean {
440
+ return /^[A-Za-z0-9._:-]+$/.test(name) && !name.includes('..');
441
+ }
442
+
443
+ function newestFile(dir: string, pattern: RegExp): string | null {
444
+ try {
445
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
446
+ .filter(e => e.isFile() && pattern.test(e.name))
447
+ .map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
448
+ .sort((a, b) => b.mtime - a.mtime);
449
+ return entries[0]?.p ?? null;
450
+ } catch { return null; }
451
+ }
452
+
453
+ /**
454
+ * Like newestFile but only returns a candidate when its mtime is within
455
+ * the recent activity window. Prevents the dashboard from surfacing a
456
+ * prior session's transcript when the daemon's sessionId doesn't match
457
+ * any file on disk (e.g. claude allocates its own uuid; daemon and
458
+ * agent disagree about what the "current" session is).
459
+ */
460
+ const RECENT_WINDOW_MS = 5 * 60 * 1000;
461
+ function newestRecentFile(dir: string, pattern: RegExp): string | null {
462
+ try {
463
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
464
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
465
+ .filter(e => e.isFile() && pattern.test(e.name))
466
+ .map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
467
+ .filter(e => e.mtime >= cutoff)
468
+ .sort((a, b) => b.mtime - a.mtime);
469
+ return entries[0]?.p ?? null;
470
+ } catch { return null; }
471
+ }
472
+
473
+ function safeMtime(p: string): number {
474
+ try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
475
+ }
476
+
477
+ /**
478
+ * File creation time in ms. birthtimeMs is high-precision on all shipped
479
+ * runners (NTFS/ext4/APFS), and a conversation .db is created by the CLI child
480
+ * strictly AFTER the daemon spawned it, so birthtime > the session's spawn
481
+ * floor for its own store. Falls back to mtime when birthtime is unavailable
482
+ * (0 / not tracked) so the caller still has a usable ordering key.
483
+ */
484
+ function safeBirthtime(p: string): number {
485
+ try {
486
+ const st = fs.statSync(p);
487
+ const birth = Math.floor(st.birthtimeMs);
488
+ return birth > 0 ? birth : Math.floor(st.mtimeMs);
489
+ } catch { return 0; }
490
+ }
491
+
492
+ function safeSize(p: string): number {
493
+ try { return fs.statSync(p).size; } catch { return 0; }
494
+ }
495
+
496
+ function normalizeRole(r: any): 'user' | 'assistant' | 'system' {
497
+ const s = String(r ?? '').toLowerCase();
498
+ if (s === 'user' || s === 'human') return 'user';
499
+ if (s === 'assistant' || s === 'ai' || s === 'model') return 'assistant';
500
+ // daemon's chat schema rejects 'tool'/'function' — surface as assistant.
501
+ if (s === 'tool' || s === 'tool_result' || s === 'function') return 'assistant';
502
+ return 'system';
503
+ }