@adhdev/daemon-core 0.9.82-rc.45 → 0.9.82-rc.451

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 (429) 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 +29 -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.d.ts +279 -2
  56. package/dist/commands/upgrade-helper.d.ts +41 -1
  57. package/dist/config/chat-history.d.ts +9 -0
  58. package/dist/config/config.d.ts +5 -0
  59. package/dist/config/mesh-config.d.ts +129 -1
  60. package/dist/config/mesh-json-config.d.ts +199 -0
  61. package/dist/config/repo-settings.d.ts +77 -0
  62. package/dist/daemon/dev-server.d.ts +0 -2
  63. package/dist/detection/ide-detector.d.ts +13 -0
  64. package/dist/detection/win32-ide-version.d.ts +37 -0
  65. package/dist/git/change-impact-config.d.ts +159 -0
  66. package/dist/git/git-commands.d.ts +12 -1
  67. package/dist/git/git-diff.d.ts +6 -0
  68. package/dist/git/git-executor.d.ts +11 -0
  69. package/dist/git/git-status.d.ts +57 -0
  70. package/dist/git/git-types.d.ts +2 -50
  71. package/dist/git/git-worktree.d.ts +71 -1
  72. package/dist/git/index.d.ts +3 -1
  73. package/dist/index.d.ts +66 -14
  74. package/dist/index.js +49753 -18414
  75. package/dist/index.js.map +1 -1
  76. package/dist/index.mjs +49614 -18438
  77. package/dist/index.mjs.map +1 -1
  78. package/dist/installer.d.ts +1 -4
  79. package/dist/ipc/local-ipc-server.d.ts +91 -0
  80. package/dist/launch.d.ts +1 -1
  81. package/dist/logging/async-batch-writer.d.ts +10 -0
  82. package/dist/logging/log-redactor.d.ts +24 -0
  83. package/dist/logging/log-tail-reader.d.ts +81 -0
  84. package/dist/logging/logger.d.ts +1 -1
  85. package/dist/mesh/contracts.d.ts +164 -0
  86. package/dist/mesh/coordinator-prompt.d.ts +89 -0
  87. package/dist/mesh/coordinator-registry.d.ts +59 -0
  88. package/dist/mesh/mesh-active-work.d.ts +174 -0
  89. package/dist/mesh/mesh-clone-grace.d.ts +8 -0
  90. package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
  91. package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
  92. package/dist/mesh/mesh-event-classify.d.ts +5 -0
  93. package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
  94. package/dist/mesh/mesh-event-trace.d.ts +21 -0
  95. package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
  96. package/dist/mesh/mesh-events-pending.d.ts +69 -0
  97. package/dist/mesh/mesh-events-stale.d.ts +61 -0
  98. package/dist/mesh/mesh-events-utils.d.ts +75 -0
  99. package/dist/mesh/mesh-events.d.ts +6 -49
  100. package/dist/mesh/mesh-fast-forward.d.ts +81 -0
  101. package/dist/mesh/mesh-host-ownership.d.ts +29 -0
  102. package/dist/mesh/mesh-init.d.ts +128 -0
  103. package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
  104. package/dist/mesh/mesh-ledger.d.ts +115 -1
  105. package/dist/mesh/mesh-magi-status.d.ts +63 -0
  106. package/dist/mesh/mesh-missions.d.ts +189 -0
  107. package/dist/mesh/mesh-node-identity.d.ts +306 -0
  108. package/dist/mesh/mesh-queue-assignment.d.ts +113 -0
  109. package/dist/mesh/mesh-reconcile-loop.d.ts +79 -0
  110. package/dist/mesh/mesh-refine-batch.d.ts +68 -0
  111. package/dist/mesh/mesh-refine-gates.d.ts +428 -0
  112. package/dist/mesh/mesh-refine-status.d.ts +62 -0
  113. package/dist/mesh/mesh-review-inbox.d.ts +90 -0
  114. package/dist/mesh/mesh-routing.d.ts +70 -0
  115. package/dist/mesh/mesh-runtime-store.d.ts +450 -0
  116. package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
  117. package/dist/mesh/mesh-task-inflight.d.ts +46 -0
  118. package/dist/mesh/mesh-task-stats.d.ts +49 -0
  119. package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
  120. package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
  121. package/dist/mesh/mesh-work-queue.d.ts +300 -5
  122. package/dist/mesh/preview-freshness.d.ts +18 -0
  123. package/dist/mesh/refine-config.d.ts +216 -0
  124. package/dist/mesh/worktree-bootstrap-config.d.ts +145 -0
  125. package/dist/providers/acp-provider-instance.d.ts +5 -0
  126. package/dist/providers/approval-utils.d.ts +20 -0
  127. package/dist/providers/chat-message-normalization.d.ts +32 -1
  128. package/dist/providers/cli-provider-instance.d.ts +254 -3
  129. package/dist/providers/contracts.d.ts +149 -6
  130. package/dist/providers/external-sources.d.ts +71 -0
  131. package/dist/providers/manual-attendance.d.ts +63 -0
  132. package/dist/providers/native-history/antigravity-cli-transcript.d.ts +126 -0
  133. package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
  134. package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
  135. package/dist/providers/native-history/constants.d.ts +12 -0
  136. package/dist/providers/native-history/dispatcher.d.ts +27 -0
  137. package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
  138. package/dist/providers/native-history/index.d.ts +13 -0
  139. package/dist/providers/provider-instance-manager.d.ts +29 -0
  140. package/dist/providers/provider-instance.d.ts +23 -1
  141. package/dist/providers/provider-loader.d.ts +26 -4
  142. package/dist/providers/provider-trust.d.ts +31 -0
  143. package/dist/providers/read-chat-contract.d.ts +29 -0
  144. package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
  145. package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
  146. package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
  147. package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
  148. package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
  149. package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
  150. package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
  151. package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
  152. package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
  153. package/dist/providers/sdk/v1/index.d.ts +30 -0
  154. package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
  155. package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
  156. package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
  157. package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
  158. package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
  159. package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
  160. package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
  161. package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
  162. package/dist/providers/spec/adapter.d.ts +98 -0
  163. package/dist/providers/spec/cli-adapter.d.ts +223 -0
  164. package/dist/providers/spec/evaluator.d.ts +45 -0
  165. package/dist/providers/spec/fsm-driver.d.ts +444 -0
  166. package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
  167. package/dist/providers/spec/fsm-loader.d.ts +14 -0
  168. package/dist/providers/spec/fsm-types.d.ts +202 -0
  169. package/dist/providers/spec/native-history-executor.d.ts +41 -0
  170. package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
  171. package/dist/providers/spec/route.d.ts +4 -0
  172. package/dist/providers/spec/types.d.ts +222 -0
  173. package/dist/providers/status-monitor.d.ts +7 -7
  174. package/dist/providers/transcript-v2.d.ts +176 -0
  175. package/dist/providers/types/interactive-prompt.d.ts +84 -0
  176. package/dist/providers/working-dir.d.ts +17 -0
  177. package/dist/repo-mesh-types.d.ts +519 -13
  178. package/dist/runtime-defaults.d.ts +2 -0
  179. package/dist/session-host/managed-host.d.ts +64 -0
  180. package/dist/session-host/runtime-surface.d.ts +10 -16
  181. package/dist/sessions/registry.d.ts +6 -0
  182. package/dist/shared-types-extra.d.ts +2 -4
  183. package/dist/shared-types.d.ts +86 -55
  184. package/dist/status/normalize.d.ts +1 -1
  185. package/dist/status/normalize.js +1 -0
  186. package/dist/status/normalize.js.map +1 -1
  187. package/dist/status/normalize.mjs +1 -0
  188. package/dist/status/normalize.mjs.map +1 -1
  189. package/dist/status/reporter.d.ts +2 -0
  190. package/dist/status/snapshot.d.ts +26 -0
  191. package/dist/system/hash.d.ts +8 -0
  192. package/dist/system/load-better-sqlite3.d.ts +21 -0
  193. package/dist/types.d.ts +5 -0
  194. package/package.json +7 -3
  195. package/src/agent-stream/poller.ts +2 -3
  196. package/src/agent-stream/provider-adapter.ts +1 -1
  197. package/src/boot/daemon-lifecycle.ts +63 -12
  198. package/src/boot/process-hardening.ts +89 -0
  199. package/src/build-info.ts +73 -0
  200. package/src/chat/source-machine.ts +534 -0
  201. package/src/chat/source-resolver.ts +0 -0
  202. package/src/chat/subscription-updates.ts +20 -1
  203. package/src/cli-adapter-types.d.ts +3 -1
  204. package/src/cli-adapter-types.ts +68 -2
  205. package/src/cli-adapters/cli-script-runner.ts +421 -0
  206. package/src/cli-adapters/cli-state-engine.ts +1246 -0
  207. package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
  208. package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
  209. package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
  210. package/src/cli-adapters/provider-cli-parse.ts +19 -0
  211. package/src/cli-adapters/provider-cli-runtime.ts +56 -7
  212. package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
  213. package/src/cli-adapters/provider-cli-shared.ts +121 -11
  214. package/src/cli-adapters/pty-transport.ts +2 -1
  215. package/src/cli-adapters/pty-write-chunking.ts +106 -0
  216. package/src/cli-adapters/raw-terminal-io.ts +252 -0
  217. package/src/cli-adapters/resolve-executable.ts +204 -0
  218. package/src/cli-adapters/session-host-transport.ts +2 -1
  219. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
  220. package/src/cli-adapters/terminal-backends/types.ts +10 -3
  221. package/src/cli-adapters/terminal-screen.ts +16 -81
  222. package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
  223. package/src/commands/chat-commands-debug-bundle.ts +398 -0
  224. package/src/commands/chat-commands-read.ts +2488 -0
  225. package/src/commands/chat-commands-scope.ts +54 -0
  226. package/src/commands/chat-commands-shared.ts +114 -0
  227. package/src/commands/chat-commands-write.ts +891 -0
  228. package/src/commands/chat-commands.ts +19 -1841
  229. package/src/commands/cli-manager.ts +596 -27
  230. package/src/commands/handler.ts +841 -2
  231. package/src/commands/high-family/index.ts +28 -0
  232. package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
  233. package/src/commands/high-family/mesh-events.ts +89 -0
  234. package/src/commands/high-family/mesh-status.ts +822 -0
  235. package/src/commands/high-family/types.ts +80 -0
  236. package/src/commands/low-family/coordinator-prompt.ts +72 -0
  237. package/src/commands/low-family/daemon-lifecycle.ts +107 -0
  238. package/src/commands/low-family/diagnostics.ts +57 -0
  239. package/src/commands/low-family/index.ts +37 -0
  240. package/src/commands/low-family/mesh-ledger.ts +62 -0
  241. package/src/commands/low-family/mesh-node-logs.ts +87 -0
  242. package/src/commands/low-family/notification.ts +116 -0
  243. package/src/commands/low-family/refine-config.ts +106 -0
  244. package/src/commands/low-family/session-host.ts +274 -0
  245. package/src/commands/low-family/spec-providerdev.ts +217 -0
  246. package/src/commands/low-family/status-meta.ts +112 -0
  247. package/src/commands/low-family/types.ts +39 -0
  248. package/src/commands/med-family/cli-agent.ts +238 -0
  249. package/src/commands/med-family/fast-forward.ts +230 -0
  250. package/src/commands/med-family/ide.ts +163 -0
  251. package/src/commands/med-family/index.ts +37 -0
  252. package/src/commands/med-family/mesh-crud.ts +1253 -0
  253. package/src/commands/med-family/mesh-host-pairing.ts +234 -0
  254. package/src/commands/med-family/mesh-queue.ts +167 -0
  255. package/src/commands/med-family/mesh-restart.ts +92 -0
  256. package/src/commands/med-family/types.ts +153 -0
  257. package/src/commands/mesh-coordinator.ts +334 -124
  258. package/src/commands/router.ts +2893 -3536
  259. package/src/commands/stream-commands.ts +8 -0
  260. package/src/commands/upgrade-helper.ts +310 -45
  261. package/src/config/chat-history.ts +493 -24
  262. package/src/config/config.ts +12 -0
  263. package/src/config/mesh-config.ts +619 -23
  264. package/src/config/mesh-json-config.ts +376 -0
  265. package/src/config/recent-activity.ts +8 -2
  266. package/src/config/repo-settings.ts +111 -0
  267. package/src/daemon/dev-auto-implement.ts +3 -2
  268. package/src/daemon/dev-cli-debug.ts +10 -1
  269. package/src/daemon/dev-server.ts +0 -541
  270. package/src/detection/cli-detector.ts +28 -9
  271. package/src/detection/ide-detector.ts +55 -16
  272. package/src/detection/win32-ide-version.ts +106 -0
  273. package/src/git/change-impact-config.ts +354 -0
  274. package/src/git/git-commands.ts +78 -15
  275. package/src/git/git-diff.ts +81 -11
  276. package/src/git/git-executor.ts +12 -0
  277. package/src/git/git-status.ts +767 -48
  278. package/src/git/git-types.ts +14 -62
  279. package/src/git/git-worktree.ts +261 -4
  280. package/src/git/index.ts +17 -0
  281. package/src/index.ts +198 -12
  282. package/src/installer.d.ts +1 -1
  283. package/src/installer.ts +8 -6
  284. package/src/ipc/local-ipc-server.ts +278 -0
  285. package/src/launch.d.ts +1 -1
  286. package/src/launch.ts +37 -28
  287. package/src/logging/async-batch-writer.ts +55 -0
  288. package/src/logging/command-log.ts +7 -5
  289. package/src/logging/log-redactor.ts +100 -0
  290. package/src/logging/log-tail-reader.ts +341 -0
  291. package/src/logging/logger.ts +14 -7
  292. package/src/mesh/contracts.ts +338 -0
  293. package/src/mesh/coordinator-prompt.ts +416 -34
  294. package/src/mesh/coordinator-registry.ts +121 -0
  295. package/src/mesh/mesh-active-work.ts +645 -0
  296. package/src/mesh/mesh-clone-grace.ts +68 -0
  297. package/src/mesh/mesh-coordinator-config.ts +97 -0
  298. package/src/mesh/mesh-delivery-policy.ts +315 -0
  299. package/src/mesh/mesh-event-classify.ts +51 -0
  300. package/src/mesh/mesh-event-forwarding.ts +1897 -0
  301. package/src/mesh/mesh-event-trace.ts +67 -0
  302. package/src/mesh/mesh-events-coordinator.ts +32 -0
  303. package/src/mesh/mesh-events-pending.ts +656 -0
  304. package/src/mesh/mesh-events-stale.ts +389 -0
  305. package/src/mesh/mesh-events-utils.ts +443 -0
  306. package/src/mesh/mesh-events.ts +33 -1035
  307. package/src/mesh/mesh-fast-forward.ts +843 -0
  308. package/src/mesh/mesh-host-ownership.ts +111 -0
  309. package/src/mesh/mesh-init.ts +350 -0
  310. package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
  311. package/src/mesh/mesh-ledger.ts +841 -102
  312. package/src/mesh/mesh-magi-status.ts +223 -0
  313. package/src/mesh/mesh-missions.ts +449 -0
  314. package/src/mesh/mesh-node-identity.ts +1985 -0
  315. package/src/mesh/mesh-queue-assignment.ts +1924 -0
  316. package/src/mesh/mesh-reconcile-loop.ts +2018 -0
  317. package/src/mesh/mesh-refine-batch.ts +205 -0
  318. package/src/mesh/mesh-refine-gates.ts +1673 -0
  319. package/src/mesh/mesh-refine-status.ts +231 -0
  320. package/src/mesh/mesh-review-inbox.ts +307 -0
  321. package/src/mesh/mesh-routing.ts +291 -0
  322. package/src/mesh/mesh-runtime-store.ts +1853 -0
  323. package/src/mesh/mesh-scheduling-runtime.ts +198 -0
  324. package/src/mesh/mesh-task-inflight.ts +70 -0
  325. package/src/mesh/mesh-task-stats.ts +161 -0
  326. package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
  327. package/src/mesh/mesh-warmup-deadline.ts +152 -0
  328. package/src/mesh/mesh-work-queue.ts +1254 -141
  329. package/src/mesh/preview-freshness.ts +118 -0
  330. package/src/mesh/refine-config.ts +423 -0
  331. package/src/mesh/worktree-bootstrap-config.ts +450 -0
  332. package/src/providers/acp-provider-instance.ts +43 -10
  333. package/src/providers/approval-utils.d.ts +5 -0
  334. package/src/providers/approval-utils.ts +57 -5
  335. package/src/providers/chat-message-normalization.ts +92 -4
  336. package/src/providers/cli-provider-instance.ts +2177 -107
  337. package/src/providers/contracts.d.ts +55 -0
  338. package/src/providers/contracts.ts +160 -6
  339. package/src/providers/extension-provider-instance.ts +12 -7
  340. package/src/providers/external-sources.ts +218 -0
  341. package/src/providers/ide-provider-instance.ts +35 -12
  342. package/src/providers/manual-attendance.ts +85 -0
  343. package/src/providers/native-history/antigravity-cli-transcript.ts +1043 -0
  344. package/src/providers/native-history/claude-cli-transcript.ts +396 -0
  345. package/src/providers/native-history/codex-cli-transcript.ts +479 -0
  346. package/src/providers/native-history/constants.ts +19 -0
  347. package/src/providers/native-history/dispatcher.ts +373 -0
  348. package/src/providers/native-history/hermes-cli-transcript.ts +260 -0
  349. package/src/providers/native-history/index.ts +30 -0
  350. package/src/providers/provider-instance-manager.ts +71 -0
  351. package/src/providers/provider-instance.ts +19 -1
  352. package/src/providers/provider-loader.ts +668 -50
  353. package/src/providers/provider-schema.ts +87 -14
  354. package/src/providers/provider-trust.ts +114 -0
  355. package/src/providers/read-chat-contract.ts +76 -16
  356. package/src/providers/sdk/README.md +49 -0
  357. package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
  358. package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
  359. package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
  360. package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
  361. package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
  362. package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
  363. package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
  364. package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
  365. package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
  366. package/src/providers/sdk/v1/index.ts +152 -0
  367. package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
  368. package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
  369. package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
  370. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +509 -0
  371. package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
  372. package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
  373. package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
  374. package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
  375. package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
  376. package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
  377. package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
  378. package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
  379. package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
  380. package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
  381. package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
  382. package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
  383. package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
  384. package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
  385. package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
  386. package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
  387. package/src/providers/sdk/v1/types/cli/index.ts +365 -0
  388. package/src/providers/sdk/v1/types/common/index.ts +229 -0
  389. package/src/providers/sdk/v1/validators/index.ts +19 -0
  390. package/src/providers/sdk/v1/validators/manifest.ts +110 -0
  391. package/src/providers/sdk/v1/validators/taint.ts +309 -0
  392. package/src/providers/spec/adapter.ts +246 -0
  393. package/src/providers/spec/cli-adapter.ts +1064 -0
  394. package/src/providers/spec/evaluator.ts +407 -0
  395. package/src/providers/spec/fsm-driver.ts +1481 -0
  396. package/src/providers/spec/fsm-evaluator.ts +290 -0
  397. package/src/providers/spec/fsm-loader.ts +128 -0
  398. package/src/providers/spec/fsm-types.ts +301 -0
  399. package/src/providers/spec/native-history-executor.ts +1174 -0
  400. package/src/providers/spec/pre-launch-trust.ts +104 -0
  401. package/src/providers/spec/route.ts +51 -0
  402. package/src/providers/spec/types.ts +262 -0
  403. package/src/providers/status-monitor.d.ts +7 -7
  404. package/src/providers/status-monitor.ts +37 -22
  405. package/src/providers/transcript-v2.ts +567 -0
  406. package/src/providers/types/interactive-prompt.ts +536 -0
  407. package/src/providers/version-archive.ts +64 -24
  408. package/src/providers/working-dir.ts +23 -0
  409. package/src/repo-mesh-types.ts +758 -14
  410. package/src/runtime-defaults.ts +39 -0
  411. package/src/session-host/managed-host.ts +218 -0
  412. package/src/session-host/runtime-surface.ts +20 -80
  413. package/src/sessions/registry.ts +6 -0
  414. package/src/shared-types-extra.ts +2 -4
  415. package/src/shared-types.d.ts +8 -0
  416. package/src/shared-types.ts +124 -55
  417. package/src/status/builders.ts +26 -6
  418. package/src/status/normalize.ts +2 -0
  419. package/src/status/reporter.ts +19 -1
  420. package/src/status/snapshot.ts +95 -26
  421. package/src/system/hash.ts +23 -0
  422. package/src/system/host-memory.ts +29 -12
  423. package/src/system/load-better-sqlite3.ts +68 -0
  424. package/src/types.ts +5 -0
  425. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  426. package/dist/mesh/mesh-sync.d.ts +0 -53
  427. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  428. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
  429. package/src/mesh/mesh-sync.ts +0 -111
@@ -0,0 +1,373 @@
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
+
23
+ export type ReaderId = 'claude-cli' | 'codex-cli' | 'antigravity-cli' | 'hermes-cli';
24
+
25
+ export interface NativeHistoryInput {
26
+ agentType?: string;
27
+ sessionId?: string;
28
+ providerSessionId?: string;
29
+ historySessionId?: string;
30
+ workspace?: string;
31
+ sessionStartedAtMs?: number;
32
+ format?: string;
33
+ watchPath?: string;
34
+ forceRefresh?: boolean;
35
+ args?: Record<string, unknown>;
36
+ }
37
+
38
+ export interface NativeHistoryResult {
39
+ messages: Array<{ role: string; content: string; receivedAt?: number; kind?: string; workspace?: string }>;
40
+ providerSessionId?: string;
41
+ sourcePath: string;
42
+ sourceMtimeMs: number;
43
+ nativeHistoryCoverage?: 'full' | 'partial' | 'best-effort';
44
+ }
45
+
46
+ export function createNativeHistoryDispatcher(reader: ReaderId): (input: NativeHistoryInput) => NativeHistoryResult | null {
47
+ return (input: NativeHistoryInput) => {
48
+ const workspace = input.workspace || '';
49
+ const sessionId = input.sessionId || input.historySessionId || '';
50
+ // Caller may pass a providerSessionId (the *provider's own* id, e.g.
51
+ // the uuid claude writes into the jsonl basename). When present, the
52
+ // dispatcher only returns a transcript whose file id matches —
53
+ // otherwise the newest_by_mtime fallback can surface a different
54
+ // session's chat (round 9 part b: the user reported "previous chat
55
+ // shows up before I type anything" on every provider).
56
+ const requestedProviderSid = input.providerSessionId || '';
57
+
58
+ const sessionStartedAtMs = typeof input.sessionStartedAtMs === 'number'
59
+ ? input.sessionStartedAtMs
60
+ : typeof input.args?.sessionStartedAtMs === 'number'
61
+ ? input.args.sessionStartedAtMs
62
+ : 0;
63
+ const sourcePath = resolveSourcePath(reader, workspace, sessionId, sessionStartedAtMs);
64
+ if (!sourcePath) return null;
65
+ if (input.forceRefresh === true || input.args?.forceRefresh === true) {
66
+ try { fs.statSync(sourcePath); } catch { /* best-effort metadata refresh */ }
67
+ }
68
+
69
+ const session = readByReader(reader, sourcePath, sessionId, workspace, requestedProviderSid);
70
+ if (!session) return null;
71
+
72
+ if (requestedProviderSid && session.providerSessionId && session.providerSessionId !== requestedProviderSid) {
73
+ return null;
74
+ }
75
+
76
+ return {
77
+ messages: session.messages.map((m: any) => ({
78
+ role: normalizeRole(m.role),
79
+ content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
80
+ receivedAt: typeof m.receivedAt === 'number' ? m.receivedAt : Date.parse(m.timestamp || '') || Date.now(),
81
+ kind: typeof m.kind === 'string' ? m.kind : 'standard',
82
+ workspace: typeof m.workspace === 'string' ? m.workspace : workspace || undefined,
83
+ })),
84
+ providerSessionId: session.providerSessionId,
85
+ sourcePath: session.sourcePath,
86
+ sourceMtimeMs: session.sourceMtimeMs,
87
+ nativeHistoryCoverage: (session as any).nativeHistoryCoverage || 'full',
88
+ };
89
+ };
90
+ }
91
+
92
+ // ────────────────────────────────────────────────────────────────────────────
93
+ // Per-provider path resolution
94
+ // ────────────────────────────────────────────────────────────────────────────
95
+
96
+ function resolveSourcePath(reader: ReaderId, workspace: string, sessionId: string, sessionStartedAtMs: number): string | null {
97
+ switch (reader) {
98
+ case 'claude-cli': return resolveClaudePath(workspace, sessionId);
99
+ case 'codex-cli': return resolveCodexPath(workspace, sessionId, sessionStartedAtMs);
100
+ case 'antigravity-cli': return resolveAntigravityPath(workspace, sessionId);
101
+ case 'hermes-cli': return resolveHermesPath(workspace, sessionId);
102
+ }
103
+ }
104
+
105
+ function resolveClaudePath(workspace: string, sessionId: string): string | null {
106
+ // claude stores per-cwd: ~/.claude/projects/<cwd-as-dashes>/<uuid>.jsonl
107
+ const dir = path.join(os.homedir(), '.claude', 'projects', cwdAsDashes(workspace));
108
+ if (!fs.existsSync(dir)) return null;
109
+ if (sessionId) {
110
+ const candidate = path.join(dir, `${sessionId}.jsonl`);
111
+ if (fs.existsSync(candidate)) return candidate;
112
+ }
113
+ // No exact match: return null. The newest_by_mtime fallback used to
114
+ // grab whichever transcript was touched most recently, but that
115
+ // surfaced a different (often the user's *external* claude session
116
+ // in the same workspace) chat in the dashboard before the user
117
+ // typed anything. The right answer is to show nothing until either
118
+ // the daemon's sessionId actually maps to a file or the caller
119
+ // passes the correct providerSessionId (round 9 part b).
120
+ return null;
121
+ }
122
+
123
+ function resolveCodexPath(workspace: string, sessionId: string, sessionStartedAtMs: number): string | null {
124
+ // codex stores by UTC date: ~/.codex/sessions/<year>/<month>/<day>/<file>.jsonl
125
+ const root = codexSessionsRoot();
126
+ if (sessionId && isUuidLikeSessionId(sessionId)) {
127
+ return findCodexPathBySessionId(root, sessionId);
128
+ }
129
+ return findCodexPathByRuntime(root, workspace, sessionStartedAtMs);
130
+ }
131
+
132
+ function findCodexPathBySessionId(root: string, sessionId: string): string | null {
133
+ if (!fs.existsSync(root)) return null;
134
+ const needle = sessionId.toLowerCase();
135
+ const matches: Array<{ p: string; mtime: number }> = [];
136
+ const stack: string[] = [root];
137
+ while (stack.length > 0) {
138
+ const current = stack.pop()!;
139
+ let entries: fs.Dirent[] = [];
140
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
141
+ for (const entry of entries) {
142
+ const entryPath = path.join(current, entry.name);
143
+ if (entry.isDirectory()) {
144
+ stack.push(entryPath);
145
+ continue;
146
+ }
147
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
148
+ if (!entry.name.toLowerCase().includes(needle)) continue;
149
+ if (!isSafeFilename(entry.name.replace('.jsonl', ''))) continue;
150
+ matches.push({ p: entryPath, mtime: safeMtime(entryPath) });
151
+ }
152
+ }
153
+ matches.sort((a, b) => b.mtime - a.mtime);
154
+ return matches[0]?.p ?? null;
155
+ }
156
+
157
+ function findCodexPathByRuntime(root: string, workspace: string, sessionStartedAtMs: number): string | null {
158
+ if (!fs.existsSync(root) || !workspace) return null;
159
+ const workspaceResolved = resolveRealPath(workspace);
160
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
161
+ const matches: Array<{ p: string; mtime: number; diff: number }> = [];
162
+ const stack: string[] = [root];
163
+
164
+ while (stack.length > 0) {
165
+ const current = stack.pop()!;
166
+ let entries: fs.Dirent[] = [];
167
+ try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
168
+ for (const entry of entries) {
169
+ const entryPath = path.join(current, entry.name);
170
+ if (entry.isDirectory()) {
171
+ stack.push(entryPath);
172
+ continue;
173
+ }
174
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
175
+ const mtime = safeMtime(entryPath);
176
+ if (mtime < cutoff) continue;
177
+ const meta = readCodexSessionMeta(entryPath);
178
+ if (!meta?.cwd || resolveRealPath(meta.cwd) !== workspaceResolved) continue;
179
+ const diff = sessionStartedAtMs > 0 && meta.timestampMs != null
180
+ ? Math.abs(meta.timestampMs - sessionStartedAtMs)
181
+ : 0;
182
+ if (sessionStartedAtMs > 0 && (meta.timestampMs == null || diff > SPAWN_BIND_GRACE_MS)) continue;
183
+ matches.push({ p: entryPath, mtime, diff });
184
+ }
185
+ }
186
+
187
+ matches.sort((a, b) => sessionStartedAtMs > 0
188
+ ? a.diff - b.diff || b.mtime - a.mtime
189
+ : b.mtime - a.mtime);
190
+ return matches[0]?.p ?? null;
191
+ }
192
+
193
+ function readCodexSessionMeta(filePath: string): { cwd?: string; timestampMs?: number } | null {
194
+ try {
195
+ const fd = fs.openSync(filePath, 'r');
196
+ try {
197
+ const buffer = Buffer.alloc(8192);
198
+ const bytes = fs.readSync(fd, buffer, 0, buffer.length, 0);
199
+ if (bytes <= 0) return null;
200
+ const text = buffer.subarray(0, bytes).toString('utf8');
201
+ const firstLine = text.slice(0, text.indexOf('\n') >= 0 ? text.indexOf('\n') : text.length).trim();
202
+ if (!firstLine) return null;
203
+ const record = JSON.parse(firstLine) as Record<string, unknown>;
204
+ if (record.type !== 'session_meta' || !record.payload || typeof record.payload !== 'object') return null;
205
+ const payload = record.payload as Record<string, unknown>;
206
+ const timestampRaw = payload.timestamp;
207
+ const timestampMs = typeof timestampRaw === 'string'
208
+ ? Date.parse(timestampRaw)
209
+ : typeof timestampRaw === 'number'
210
+ ? (timestampRaw < 1e12 ? timestampRaw * 1000 : timestampRaw)
211
+ : NaN;
212
+ return {
213
+ cwd: typeof payload.cwd === 'string' ? payload.cwd : undefined,
214
+ timestampMs: Number.isFinite(timestampMs) ? timestampMs : undefined,
215
+ };
216
+ } finally {
217
+ fs.closeSync(fd);
218
+ }
219
+ } catch {
220
+ return null;
221
+ }
222
+ }
223
+
224
+ function resolveRealPath(value: string): string {
225
+ try { return fs.realpathSync(value); } catch { return value; }
226
+ }
227
+
228
+ function resolveAntigravityPath(workspace: string, sessionId: string): string | null {
229
+ void workspace;
230
+ const agyRoot = path.join(os.homedir(), '.gemini', 'antigravity-cli');
231
+
232
+ // (1) Exact session bind: current antigravity writes a per-session SQLite db
233
+ // at conversations/<uuid>.db. If the caller knows the session id and the
234
+ // db exists, bind straight to it — this is the authoritative source and
235
+ // carries the assistant answers the brain/pty path was losing.
236
+ if (sessionId && isUuidLikeSessionId(sessionId)) {
237
+ const dbPath = path.join(agyRoot, 'conversations', `${sessionId}.db`);
238
+ if (fs.existsSync(dbPath)) return dbPath;
239
+ }
240
+
241
+ // (2) brain/<uuid>/.system_generated/logs/transcript.jsonl (legacy full source).
242
+ // Only bind to a brain transcript that is NON-EMPTY: current antigravity
243
+ // writes this file but leaves it 0 bytes (all real conversation data now
244
+ // lives in the per-session .db), so an empty transcript here would
245
+ // otherwise shadow the .db fallback below and return no messages. Skip
246
+ // empty transcripts so an unbound read still reaches the .db.
247
+ const brainRoot = path.join(agyRoot, 'brain');
248
+ if (fs.existsSync(brainRoot)) {
249
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
250
+ const entries = fs.readdirSync(brainRoot, { withFileTypes: true })
251
+ .filter(e => e.isDirectory())
252
+ .map(e => ({ p: path.join(brainRoot, e.name), mtime: safeMtime(path.join(brainRoot, e.name)) }))
253
+ .filter(e => e.mtime >= cutoff)
254
+ .sort((a, b) => b.mtime - a.mtime);
255
+ for (const e of entries) {
256
+ const t = path.join(e.p, '.system_generated', 'logs', 'transcript.jsonl');
257
+ if (fs.existsSync(t) && safeSize(t) > 0) return t;
258
+ }
259
+ }
260
+
261
+ // (3) No brain transcript and no bound session id: fall back to the most
262
+ // recently touched conversations/<uuid>.db (within the recency window).
263
+ const convRoot = path.join(agyRoot, 'conversations');
264
+ const newestDb = newestRecentFile(convRoot, /^[0-9a-f-]+\.db$/i);
265
+ if (newestDb) return newestDb;
266
+
267
+ return null;
268
+ }
269
+
270
+ function resolveHermesPath(workspace: string, sessionId: string): string | null {
271
+ void workspace; void sessionId;
272
+ // Hermes ≥ 0.14 persists all chat to ~/.hermes/state.db (SQLite). The
273
+ // db file is the "path" we hand to the reader — it pulls the newest
274
+ // source='cli' session inside readSession.
275
+ const dbPath = path.join(os.homedir(), '.hermes', 'state.db');
276
+ if (fs.existsSync(dbPath)) return dbPath;
277
+ // Legacy fallback: pre-db hermes wrote per-session JSON dumps.
278
+ const dir = path.join(os.homedir(), '.hermes', 'sessions');
279
+ if (!fs.existsSync(dir)) return null;
280
+ return newestRecentFile(dir, /^session_.*\.json$/);
281
+ }
282
+
283
+ // ────────────────────────────────────────────────────────────────────────────
284
+ // Reader dispatch
285
+ // ────────────────────────────────────────────────────────────────────────────
286
+
287
+ function readByReader(
288
+ reader: ReaderId,
289
+ sourcePath: string,
290
+ sessionId: string,
291
+ workspace: string,
292
+ requestedProviderSid: string,
293
+ ): any | null {
294
+ switch (reader) {
295
+ case 'claude-cli': return readClaudeCliSession(sourcePath);
296
+ case 'codex-cli': return readCodexCliSession(sourcePath);
297
+ case 'antigravity-cli': return readAntigravityCliSession(sourcePath, sessionId || undefined, workspace || undefined);
298
+ // hermes reads a *shared* state.db and would otherwise pick the newest
299
+ // source='cli' session, which drifts every read (hermes ≥0.14 writes a
300
+ // fresh row per internal sub-session). Pass the bound id so it reads
301
+ // THAT session directly instead of newest-wins. claude/codex resolve a
302
+ // per-session file upstream, so they need no equivalent pin here.
303
+ case 'hermes-cli': return readHermesCliSession(sourcePath, requestedProviderSid || undefined);
304
+ }
305
+ }
306
+
307
+ // ────────────────────────────────────────────────────────────────────────────
308
+ // Helpers
309
+ // ────────────────────────────────────────────────────────────────────────────
310
+
311
+ function cwdAsDashes(cwd: string): string {
312
+ if (!cwd) return '';
313
+ return cwd.replace(/\//g, '-');
314
+ }
315
+
316
+ function codexSessionsRoot(): string {
317
+ return path.join(os.homedir(), '.codex', 'sessions');
318
+ }
319
+
320
+ function isUuidLikeSessionId(sessionId: string): boolean {
321
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
322
+ }
323
+
324
+ function isSafeFilename(name: string): boolean {
325
+ return /^[A-Za-z0-9._:-]+$/.test(name) && !name.includes('..');
326
+ }
327
+
328
+ function newestFile(dir: string, pattern: RegExp): string | null {
329
+ try {
330
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
331
+ .filter(e => e.isFile() && pattern.test(e.name))
332
+ .map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
333
+ .sort((a, b) => b.mtime - a.mtime);
334
+ return entries[0]?.p ?? null;
335
+ } catch { return null; }
336
+ }
337
+
338
+ /**
339
+ * Like newestFile but only returns a candidate when its mtime is within
340
+ * the recent activity window. Prevents the dashboard from surfacing a
341
+ * prior session's transcript when the daemon's sessionId doesn't match
342
+ * any file on disk (e.g. claude allocates its own uuid; daemon and
343
+ * agent disagree about what the "current" session is).
344
+ */
345
+ const RECENT_WINDOW_MS = 5 * 60 * 1000;
346
+ function newestRecentFile(dir: string, pattern: RegExp): string | null {
347
+ try {
348
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
349
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
350
+ .filter(e => e.isFile() && pattern.test(e.name))
351
+ .map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
352
+ .filter(e => e.mtime >= cutoff)
353
+ .sort((a, b) => b.mtime - a.mtime);
354
+ return entries[0]?.p ?? null;
355
+ } catch { return null; }
356
+ }
357
+
358
+ function safeMtime(p: string): number {
359
+ try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
360
+ }
361
+
362
+ function safeSize(p: string): number {
363
+ try { return fs.statSync(p).size; } catch { return 0; }
364
+ }
365
+
366
+ function normalizeRole(r: any): 'user' | 'assistant' | 'system' {
367
+ const s = String(r ?? '').toLowerCase();
368
+ if (s === 'user' || s === 'human') return 'user';
369
+ if (s === 'assistant' || s === 'ai' || s === 'model') return 'assistant';
370
+ // daemon's chat schema rejects 'tool'/'function' — surface as assistant.
371
+ if (s === 'tool' || s === 'tool_result' || s === 'function') return 'assistant';
372
+ return 'system';
373
+ }
@@ -0,0 +1,260 @@
1
+ /**
2
+ * Hermes Agent — native history adapter.
3
+ *
4
+ * Hermes persists state in ~/.hermes/state.db (SQLite, better-sqlite3):
5
+ * sessions(id, source, started_at, ended_at, message_count, ...)
6
+ * messages(id, session_id, role, content, timestamp, ...)
7
+ *
8
+ * Earlier releases dumped per-session JSON files under ~/.hermes/sessions/;
9
+ * recent hermes (≥ 0.14) writes only to state.db. We read straight from
10
+ * the db when available and fall back to scanning legacy JSON dumps for
11
+ * archived sessions.
12
+ *
13
+ * The dispatcher hands us a sourcePath (the file the resolveHermesPath
14
+ * function picks). For the SQLite case the "path" is the db file itself
15
+ * and we resolve the most recent cli-source session inside readSession.
16
+ */
17
+ 'use strict';
18
+
19
+ import * as fs from 'node:fs';
20
+ import * as path from 'node:path';
21
+ import * as os from 'node:os';
22
+ import { loadBetterSqlite3 } from '../../system/load-better-sqlite3.js';
23
+
24
+ export interface NativeHistoryMessage {
25
+ id: string;
26
+ role: 'user' | 'assistant' | 'system';
27
+ content: string;
28
+ receivedAt: number;
29
+ kind?: string;
30
+ }
31
+
32
+ export interface NativeHistorySession {
33
+ messages: NativeHistoryMessage[];
34
+ providerSessionId: string;
35
+ source: 'provider-native';
36
+ sourcePath: string;
37
+ sourceMtimeMs: number;
38
+ nativeHistoryCoverage: 'full';
39
+ workspace?: string;
40
+ }
41
+
42
+ export interface NativeHistorySessionMeta {
43
+ historySessionId: string;
44
+ sessionId: string;
45
+ sourcePath: string;
46
+ sourceMtimeMs: number;
47
+ messageCount: number;
48
+ firstMessageAt: number;
49
+ lastMessageAt: number;
50
+ sessionTitle?: string;
51
+ preview?: string;
52
+ workspace?: string;
53
+ }
54
+
55
+ const HERMES_STATE_DB = path.join(os.homedir(), '.hermes', 'state.db');
56
+ const HERMES_LEGACY_SESSIONS_DIR = path.join(os.homedir(), '.hermes', 'sessions');
57
+
58
+ function statMtimeMs(p: string): number {
59
+ try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
60
+ }
61
+
62
+ function openDb(): any | null {
63
+ if (!fs.existsSync(HERMES_STATE_DB)) return null;
64
+ try {
65
+ const Database = loadBetterSqlite3();
66
+ return new Database(HERMES_STATE_DB, { readonly: true, fileMustExist: true });
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ function loadMessagesForSession(db: any, sessionId: string): NativeHistoryMessage[] {
73
+ // Assistant turns whose finish_reason='tool_calls' persist an EMPTY
74
+ // `content` — their payload lives in the `tool_calls` column. Filtering on
75
+ // `content != ''` alone drops those rows, so a turn whose terminal message
76
+ // is a tool call surfaces zero assistant bubbles. Accept a row when either
77
+ // `content` OR `tool_calls` is non-empty, and project `tool_calls` into the
78
+ // content slot when `content` is empty so the bubble still carries text.
79
+ const rows: any[] = db.prepare(
80
+ `SELECT id, role, COALESCE(NULLIF(content, ''), tool_calls) AS content, timestamp
81
+ FROM messages
82
+ WHERE session_id = ?
83
+ AND ((content IS NOT NULL AND content != '') OR (tool_calls IS NOT NULL AND tool_calls != ''))
84
+ ORDER BY timestamp ASC, id ASC`,
85
+ ).all(sessionId);
86
+ const out: NativeHistoryMessage[] = [];
87
+ for (const r of rows) {
88
+ const role = normalizeHermesRole(r.role);
89
+ // Hermes stores some tool/system rows under role='tool'; surface as
90
+ // 'assistant' so they don't get dropped on the daemon's chat schema
91
+ // validation (role must be user/assistant/system).
92
+ out.push({
93
+ id: String(r.id),
94
+ role,
95
+ content: String(r.content),
96
+ receivedAt: Math.floor(Number(r.timestamp) * 1000),
97
+ kind: 'standard',
98
+ });
99
+ }
100
+ return out;
101
+ }
102
+
103
+ export function readSession(sessionPath: string, requestedSessionId?: string): NativeHistorySession | null {
104
+ if (!sessionPath) return null;
105
+
106
+ // Path mode A: SQLite — sourcePath is the state.db path.
107
+ if (sessionPath === HERMES_STATE_DB) {
108
+ const db = openDb();
109
+ if (!db) return null;
110
+ try {
111
+ const pinned = String(requestedSessionId || '').trim();
112
+ let sessionId: string;
113
+ if (pinned) {
114
+ // Session pin: the caller is already bound to a specific
115
+ // provider session, so read THAT session directly instead of
116
+ // the newest-wins pick below. hermes ≥0.14 writes a fresh
117
+ // `sessions` row per internal sub-session, so an unpinned
118
+ // `ORDER BY started_at DESC LIMIT 1` drifts to a different id
119
+ // on every read → re-bind churn + reading completion evidence
120
+ // from the wrong session. loadMessagesForSession returning
121
+ // rows validates the id exists.
122
+ sessionId = pinned;
123
+ } else {
124
+ // No bound id yet (discovery): pick the newest source='cli'
125
+ // session that has at least one persisted message. Use an
126
+ // EXISTS check against `messages` rather than the denormalized
127
+ // `message_count` column — a freshly-started session already
128
+ // has message rows while `message_count` (DEFAULT 0) can still
129
+ // lag at 0, and the old predicate excluded exactly that
130
+ // just-created session, resolving to nothing.
131
+ const row: any = db.prepare(
132
+ `SELECT id, started_at FROM sessions
133
+ WHERE source = 'cli'
134
+ AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = sessions.id)
135
+ ORDER BY started_at DESC LIMIT 1`,
136
+ ).get();
137
+ if (!row) return null;
138
+ sessionId = String(row.id);
139
+ }
140
+ const messages = loadMessagesForSession(db, sessionId);
141
+ if (messages.length === 0) return null;
142
+ return {
143
+ messages,
144
+ providerSessionId: sessionId,
145
+ source: 'provider-native',
146
+ sourcePath: sessionPath,
147
+ sourceMtimeMs: statMtimeMs(sessionPath),
148
+ nativeHistoryCoverage: 'full',
149
+ };
150
+ } finally {
151
+ try { db.close(); } catch { /* ignore */ }
152
+ }
153
+ }
154
+
155
+ // Path mode B: legacy JSON dump — keep the old reader for archived
156
+ // sessions that pre-date the db format.
157
+ if (!path.isAbsolute(sessionPath) || !fs.existsSync(sessionPath)) return null;
158
+ let raw: any;
159
+ try { raw = JSON.parse(fs.readFileSync(sessionPath, 'utf8')); } catch { return null; }
160
+ if (!raw || typeof raw !== 'object') return null;
161
+ const rawMessages = Array.isArray(raw.messages) ? raw.messages : [];
162
+ if (rawMessages.length === 0) return null;
163
+ const sourceMtimeMs = statMtimeMs(sessionPath);
164
+ const sessionStart = Number(raw.session_start) || sourceMtimeMs - rawMessages.length * 1000;
165
+ const messages: NativeHistoryMessage[] = [];
166
+ for (let i = 0; i < rawMessages.length; i += 1) {
167
+ const m = rawMessages[i];
168
+ const content = typeof m?.content === 'string' ? m.content : '';
169
+ if (!content) continue;
170
+ messages.push({
171
+ id: typeof m?.id === 'string' ? m.id : `msg_${i}`,
172
+ role: normalizeHermesRole(m?.role),
173
+ content,
174
+ receivedAt: sessionStart + i * 1000,
175
+ kind: 'standard',
176
+ });
177
+ }
178
+ if (messages.length === 0) return null;
179
+ const sessionId = typeof raw.session_id === 'string' && raw.session_id
180
+ ? raw.session_id
181
+ : path.basename(sessionPath, '.json').replace(/^session_/, '');
182
+ return {
183
+ messages,
184
+ providerSessionId: sessionId,
185
+ source: 'provider-native',
186
+ sourcePath: sessionPath,
187
+ sourceMtimeMs,
188
+ nativeHistoryCoverage: 'full',
189
+ };
190
+ }
191
+
192
+ export async function listSessions(_watchPath: string): Promise<NativeHistorySessionMeta[]> {
193
+ const out: NativeHistorySessionMeta[] = [];
194
+
195
+ const db = openDb();
196
+ if (db) {
197
+ try {
198
+ const rows: any[] = db.prepare(
199
+ `SELECT id, started_at, ended_at, message_count, title
200
+ FROM sessions
201
+ WHERE source = 'cli'
202
+ AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = sessions.id)
203
+ ORDER BY started_at DESC LIMIT 100`,
204
+ ).all();
205
+ const mtime = statMtimeMs(HERMES_STATE_DB);
206
+ for (const r of rows) {
207
+ out.push({
208
+ historySessionId: String(r.id),
209
+ sessionId: String(r.id),
210
+ sourcePath: HERMES_STATE_DB,
211
+ sourceMtimeMs: mtime,
212
+ messageCount: Number(r.message_count) || 0,
213
+ firstMessageAt: Math.floor(Number(r.started_at) * 1000),
214
+ lastMessageAt: Math.floor(Number(r.ended_at || r.started_at) * 1000),
215
+ sessionTitle: typeof r.title === 'string' ? r.title : undefined,
216
+ });
217
+ }
218
+ } finally {
219
+ try { db.close(); } catch { /* ignore */ }
220
+ }
221
+ }
222
+
223
+ if (fs.existsSync(HERMES_LEGACY_SESSIONS_DIR)) {
224
+ for (const name of fs.readdirSync(HERMES_LEGACY_SESSIONS_DIR)) {
225
+ if (!/^session_.*\.json$/.test(name)) continue;
226
+ const p = path.join(HERMES_LEGACY_SESSIONS_DIR, name);
227
+ const mtime = statMtimeMs(p);
228
+ if (!mtime) continue;
229
+ let raw: any;
230
+ try { raw = JSON.parse(fs.readFileSync(p, 'utf8')); } catch { continue; }
231
+ const msgs = Array.isArray(raw?.messages) ? raw.messages : [];
232
+ if (msgs.length === 0) continue;
233
+ const sessionId = typeof raw.session_id === 'string' && raw.session_id
234
+ ? raw.session_id
235
+ : name.replace(/^session_/, '').replace(/\.json$/, '');
236
+ out.push({
237
+ historySessionId: sessionId,
238
+ sessionId,
239
+ sourcePath: p,
240
+ sourceMtimeMs: mtime,
241
+ messageCount: msgs.length,
242
+ firstMessageAt: Number(raw.session_start) || mtime,
243
+ lastMessageAt: Number(raw.last_updated) || mtime,
244
+ sessionTitle: typeof raw.title === 'string' ? raw.title : undefined,
245
+ preview: typeof msgs[0]?.content === 'string' ? String(msgs[0].content).slice(0, 80) : undefined,
246
+ });
247
+ }
248
+ }
249
+
250
+ out.sort((a, b) => b.sourceMtimeMs - a.sourceMtimeMs);
251
+ return out;
252
+ }
253
+
254
+ function normalizeHermesRole(r: any): 'user' | 'assistant' | 'system' {
255
+ const s = String(r ?? '').toLowerCase();
256
+ if (s === 'user' || s === 'human') return 'user';
257
+ if (s === 'assistant' || s === 'ai' || s === 'model') return 'assistant';
258
+ if (s === 'tool' || s === 'tool_result' || s === 'function') return 'assistant';
259
+ return 'system';
260
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * native-history — Daemon-side built-in adapters for CLI provider native history.
3
+ *
4
+ * Each adapter reads conversation history directly from the CLI tool's on-disk
5
+ * storage without shelling out to a provider JS override script.
6
+ *
7
+ * OSS code (AGPL-3.0). Must not import from packages/ (proprietary).
8
+ */
9
+
10
+ export {
11
+ readSession as readClaudeCliSession,
12
+ listSessions as listClaudeCliSessions,
13
+ } from './claude-cli-transcript.js';
14
+
15
+ export {
16
+ readSession as readCodexCliSession,
17
+ listSessions as listCodexCliSessions,
18
+ } from './codex-cli-transcript.js';
19
+
20
+ export {
21
+ readSession as readAntigravityCliSession,
22
+ listSessions as listAntigravityCliSessions,
23
+ } from './antigravity-cli-transcript.js';
24
+
25
+ export {
26
+ readSession as readHermesCliSession,
27
+ listSessions as listHermesCliSessions,
28
+ } from './hermes-cli-transcript.js';
29
+
30
+ export { createNativeHistoryDispatcher, type ReaderId } from './dispatcher.js';