apex-code 0.0.1-alpha.1 → 0.0.1-alpha.2

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 (426) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +66 -681
  3. package/dist/cli/args.d.ts +5 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +45 -6
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-command.d.ts.map +1 -1
  8. package/dist/cli/auth-command.js +3 -3
  9. package/dist/cli/auth-command.js.map +1 -1
  10. package/dist/cli/cost-command.d.ts +19 -0
  11. package/dist/cli/cost-command.d.ts.map +1 -0
  12. package/dist/cli/cost-command.js +107 -0
  13. package/dist/cli/cost-command.js.map +1 -0
  14. package/dist/cli/startup-ui.d.ts +1 -1
  15. package/dist/cli/startup-ui.d.ts.map +1 -1
  16. package/dist/cli/startup-ui.js +1 -2
  17. package/dist/cli/startup-ui.js.map +1 -1
  18. package/dist/cli.d.ts.map +1 -1
  19. package/dist/cli.js +45 -16
  20. package/dist/cli.js.map +1 -1
  21. package/dist/config.d.ts +2 -2
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/config.js +14 -7
  24. package/dist/config.js.map +1 -1
  25. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  26. package/dist/core/agent-session-runtime.js +2 -0
  27. package/dist/core/agent-session-runtime.js.map +1 -1
  28. package/dist/core/agent-session-services.d.ts +9 -0
  29. package/dist/core/agent-session-services.d.ts.map +1 -1
  30. package/dist/core/agent-session-services.js +30 -4
  31. package/dist/core/agent-session-services.js.map +1 -1
  32. package/dist/core/agent-session.d.ts +46 -0
  33. package/dist/core/agent-session.d.ts.map +1 -1
  34. package/dist/core/agent-session.js +137 -19
  35. package/dist/core/agent-session.js.map +1 -1
  36. package/dist/core/auth-storage.d.ts.map +1 -1
  37. package/dist/core/auth-storage.js +6 -6
  38. package/dist/core/auth-storage.js.map +1 -1
  39. package/dist/core/bash-executor.d.ts.map +1 -1
  40. package/dist/core/bash-executor.js +1 -1
  41. package/dist/core/bash-executor.js.map +1 -1
  42. package/dist/core/context/deferred-schemas.d.ts +92 -0
  43. package/dist/core/context/deferred-schemas.d.ts.map +1 -0
  44. package/dist/core/context/deferred-schemas.js +74 -0
  45. package/dist/core/context/deferred-schemas.js.map +1 -0
  46. package/dist/core/context/eviction.d.ts +47 -0
  47. package/dist/core/context/eviction.d.ts.map +1 -0
  48. package/dist/core/context/eviction.js +83 -0
  49. package/dist/core/context/eviction.js.map +1 -0
  50. package/dist/core/context/pipeline.d.ts +90 -0
  51. package/dist/core/context/pipeline.d.ts.map +1 -0
  52. package/dist/core/context/pipeline.js +109 -0
  53. package/dist/core/context/pipeline.js.map +1 -0
  54. package/dist/core/credential-failover.d.ts +30 -0
  55. package/dist/core/credential-failover.d.ts.map +1 -0
  56. package/dist/core/credential-failover.js +46 -0
  57. package/dist/core/credential-failover.js.map +1 -0
  58. package/dist/core/credential-pool.d.ts +60 -0
  59. package/dist/core/credential-pool.d.ts.map +1 -0
  60. package/dist/core/credential-pool.js +84 -0
  61. package/dist/core/credential-pool.js.map +1 -0
  62. package/dist/core/delegation/agents.d.ts +15 -0
  63. package/dist/core/delegation/agents.d.ts.map +1 -0
  64. package/dist/core/delegation/agents.js +55 -0
  65. package/dist/core/delegation/agents.js.map +1 -0
  66. package/dist/core/delegation/ceiling.d.ts +29 -0
  67. package/dist/core/delegation/ceiling.d.ts.map +1 -0
  68. package/dist/core/delegation/ceiling.js +34 -0
  69. package/dist/core/delegation/ceiling.js.map +1 -0
  70. package/dist/core/delegation/runtime.d.ts +94 -0
  71. package/dist/core/delegation/runtime.d.ts.map +1 -0
  72. package/dist/core/delegation/runtime.js +117 -0
  73. package/dist/core/delegation/runtime.js.map +1 -0
  74. package/dist/core/durable-state/daemon.d.ts +37 -0
  75. package/dist/core/durable-state/daemon.d.ts.map +1 -0
  76. package/dist/core/durable-state/daemon.js +62 -0
  77. package/dist/core/durable-state/daemon.js.map +1 -0
  78. package/dist/core/durable-state/provenance.d.ts +7 -0
  79. package/dist/core/durable-state/provenance.d.ts.map +1 -0
  80. package/dist/core/durable-state/provenance.js +24 -0
  81. package/dist/core/durable-state/provenance.js.map +1 -0
  82. package/dist/core/durable-state/sqlite.d.ts +84 -0
  83. package/dist/core/durable-state/sqlite.d.ts.map +1 -0
  84. package/dist/core/durable-state/sqlite.js +331 -0
  85. package/dist/core/durable-state/sqlite.js.map +1 -0
  86. package/dist/core/environment.d.ts +12 -0
  87. package/dist/core/environment.d.ts.map +1 -0
  88. package/dist/core/environment.js +69 -0
  89. package/dist/core/environment.js.map +1 -0
  90. package/dist/core/evidence-policy.d.ts +17 -0
  91. package/dist/core/evidence-policy.d.ts.map +1 -0
  92. package/dist/core/evidence-policy.js +25 -0
  93. package/dist/core/evidence-policy.js.map +1 -0
  94. package/dist/core/evidence.d.ts +16 -0
  95. package/dist/core/evidence.d.ts.map +1 -0
  96. package/dist/core/evidence.js +51 -0
  97. package/dist/core/evidence.js.map +1 -0
  98. package/dist/core/experimental.d.ts.map +1 -1
  99. package/dist/core/experimental.js +2 -1
  100. package/dist/core/experimental.js.map +1 -1
  101. package/dist/core/extensions/types.d.ts +2 -0
  102. package/dist/core/extensions/types.d.ts.map +1 -1
  103. package/dist/core/extensions/types.js.map +1 -1
  104. package/dist/core/index.d.ts +1 -0
  105. package/dist/core/index.d.ts.map +1 -1
  106. package/dist/core/index.js +1 -0
  107. package/dist/core/index.js.map +1 -1
  108. package/dist/core/model-config.d.ts +8 -0
  109. package/dist/core/model-config.d.ts.map +1 -1
  110. package/dist/core/model-config.js +21 -5
  111. package/dist/core/model-config.js.map +1 -1
  112. package/dist/core/model-resolver.d.ts +20 -0
  113. package/dist/core/model-resolver.d.ts.map +1 -1
  114. package/dist/core/model-resolver.js +59 -0
  115. package/dist/core/model-resolver.js.map +1 -1
  116. package/dist/core/model-runtime.d.ts +73 -0
  117. package/dist/core/model-runtime.d.ts.map +1 -1
  118. package/dist/core/model-runtime.js +225 -8
  119. package/dist/core/model-runtime.js.map +1 -1
  120. package/dist/core/observability/aggregate.d.ts +21 -0
  121. package/dist/core/observability/aggregate.d.ts.map +1 -0
  122. package/dist/core/observability/aggregate.js +36 -0
  123. package/dist/core/observability/aggregate.js.map +1 -0
  124. package/dist/core/observability/otlp.d.ts +66 -0
  125. package/dist/core/observability/otlp.d.ts.map +1 -0
  126. package/dist/core/observability/otlp.js +95 -0
  127. package/dist/core/observability/otlp.js.map +1 -0
  128. package/dist/core/package-manager.d.ts.map +1 -1
  129. package/dist/core/package-manager.js +3 -2
  130. package/dist/core/package-manager.js.map +1 -1
  131. package/dist/core/permissions/gate.d.ts +35 -0
  132. package/dist/core/permissions/gate.d.ts.map +1 -0
  133. package/dist/core/permissions/gate.js +72 -0
  134. package/dist/core/permissions/gate.js.map +1 -0
  135. package/dist/core/permissions/modes.d.ts +18 -0
  136. package/dist/core/permissions/modes.d.ts.map +1 -0
  137. package/dist/core/permissions/modes.js +57 -0
  138. package/dist/core/permissions/modes.js.map +1 -0
  139. package/dist/core/permissions/responder.d.ts +30 -0
  140. package/dist/core/permissions/responder.d.ts.map +1 -0
  141. package/dist/core/permissions/responder.js +32 -0
  142. package/dist/core/permissions/responder.js.map +1 -0
  143. package/dist/core/permissions/rules.d.ts +34 -0
  144. package/dist/core/permissions/rules.d.ts.map +1 -0
  145. package/dist/core/permissions/rules.js +74 -0
  146. package/dist/core/permissions/rules.js.map +1 -0
  147. package/dist/core/permissions/startup.d.ts +33 -0
  148. package/dist/core/permissions/startup.d.ts.map +1 -0
  149. package/dist/core/permissions/startup.js +55 -0
  150. package/dist/core/permissions/startup.js.map +1 -0
  151. package/dist/core/permissions/store.d.ts +114 -0
  152. package/dist/core/permissions/store.d.ts.map +1 -0
  153. package/dist/core/permissions/store.js +229 -0
  154. package/dist/core/permissions/store.js.map +1 -0
  155. package/dist/core/project-trust.d.ts.map +1 -1
  156. package/dist/core/project-trust.js +1 -1
  157. package/dist/core/project-trust.js.map +1 -1
  158. package/dist/core/provider-attribution.d.ts.map +1 -1
  159. package/dist/core/provider-attribution.js +6 -7
  160. package/dist/core/provider-attribution.js.map +1 -1
  161. package/dist/core/remote-catalog-provider.d.ts +2 -2
  162. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  163. package/dist/core/remote-catalog-provider.js +20 -16
  164. package/dist/core/remote-catalog-provider.js.map +1 -1
  165. package/dist/core/sandbox/child-entry.d.ts +2 -0
  166. package/dist/core/sandbox/child-entry.d.ts.map +1 -0
  167. package/dist/core/sandbox/child-entry.js +11 -0
  168. package/dist/core/sandbox/child-entry.js.map +1 -0
  169. package/dist/core/sandbox/cli-launch.d.ts +27 -0
  170. package/dist/core/sandbox/cli-launch.d.ts.map +1 -0
  171. package/dist/core/sandbox/cli-launch.js +133 -0
  172. package/dist/core/sandbox/cli-launch.js.map +1 -0
  173. package/dist/core/sandbox/cli-supervisor.d.ts +25 -0
  174. package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -0
  175. package/dist/core/sandbox/cli-supervisor.js +57 -0
  176. package/dist/core/sandbox/cli-supervisor.js.map +1 -0
  177. package/dist/core/sandbox/linux-backend.d.ts +18 -0
  178. package/dist/core/sandbox/linux-backend.d.ts.map +1 -0
  179. package/dist/core/sandbox/linux-backend.js +186 -0
  180. package/dist/core/sandbox/linux-backend.js.map +1 -0
  181. package/dist/core/sandbox/macos-backend.d.ts +18 -0
  182. package/dist/core/sandbox/macos-backend.d.ts.map +1 -0
  183. package/dist/core/sandbox/macos-backend.js +195 -0
  184. package/dist/core/sandbox/macos-backend.js.map +1 -0
  185. package/dist/core/sandbox/network-proxy.d.ts +19 -0
  186. package/dist/core/sandbox/network-proxy.d.ts.map +1 -0
  187. package/dist/core/sandbox/network-proxy.js +79 -0
  188. package/dist/core/sandbox/network-proxy.js.map +1 -0
  189. package/dist/core/sandbox/policy.d.ts +32 -0
  190. package/dist/core/sandbox/policy.d.ts.map +1 -0
  191. package/dist/core/sandbox/policy.js +38 -0
  192. package/dist/core/sandbox/policy.js.map +1 -0
  193. package/dist/core/sandbox/supervisor.d.ts +31 -0
  194. package/dist/core/sandbox/supervisor.d.ts.map +1 -0
  195. package/dist/core/sandbox/supervisor.js +18 -0
  196. package/dist/core/sandbox/supervisor.js.map +1 -0
  197. package/dist/core/sandbox/violations.d.ts +23 -0
  198. package/dist/core/sandbox/violations.d.ts.map +1 -0
  199. package/dist/core/sandbox/violations.js +30 -0
  200. package/dist/core/sandbox/violations.js.map +1 -0
  201. package/dist/core/sdk.d.ts +20 -36
  202. package/dist/core/sdk.d.ts.map +1 -1
  203. package/dist/core/sdk.js +129 -2
  204. package/dist/core/sdk.js.map +1 -1
  205. package/dist/core/session-manager.d.ts +41 -2
  206. package/dist/core/session-manager.d.ts.map +1 -1
  207. package/dist/core/session-manager.js +57 -0
  208. package/dist/core/session-manager.js.map +1 -1
  209. package/dist/core/session-share.d.ts +16 -0
  210. package/dist/core/session-share.d.ts.map +1 -0
  211. package/dist/core/session-share.js +22 -0
  212. package/dist/core/session-share.js.map +1 -0
  213. package/dist/core/settings-manager.d.ts +38 -9
  214. package/dist/core/settings-manager.d.ts.map +1 -1
  215. package/dist/core/settings-manager.js +39 -24
  216. package/dist/core/settings-manager.js.map +1 -1
  217. package/dist/core/system-prompt.d.ts.map +1 -1
  218. package/dist/core/system-prompt.js +5 -5
  219. package/dist/core/system-prompt.js.map +1 -1
  220. package/dist/core/timings.d.ts +1 -1
  221. package/dist/core/timings.d.ts.map +1 -1
  222. package/dist/core/timings.js +3 -2
  223. package/dist/core/timings.js.map +1 -1
  224. package/dist/core/tools/ask-user.d.ts +25 -0
  225. package/dist/core/tools/ask-user.d.ts.map +1 -0
  226. package/dist/core/tools/ask-user.js +49 -0
  227. package/dist/core/tools/ask-user.js.map +1 -0
  228. package/dist/core/tools/bash-command-segments.d.ts +22 -0
  229. package/dist/core/tools/bash-command-segments.d.ts.map +1 -0
  230. package/dist/core/tools/bash-command-segments.js +128 -0
  231. package/dist/core/tools/bash-command-segments.js.map +1 -0
  232. package/dist/core/tools/bash.d.ts +26 -3
  233. package/dist/core/tools/bash.d.ts.map +1 -1
  234. package/dist/core/tools/bash.js +105 -16
  235. package/dist/core/tools/bash.js.map +1 -1
  236. package/dist/core/tools/contract.d.ts +156 -0
  237. package/dist/core/tools/contract.d.ts.map +1 -0
  238. package/dist/core/tools/contract.js +48 -0
  239. package/dist/core/tools/contract.js.map +1 -0
  240. package/dist/core/tools/delegate.d.ts +38 -0
  241. package/dist/core/tools/delegate.d.ts.map +1 -0
  242. package/dist/core/tools/delegate.js +66 -0
  243. package/dist/core/tools/delegate.js.map +1 -0
  244. package/dist/core/tools/edit.d.ts +2 -2
  245. package/dist/core/tools/edit.d.ts.map +1 -1
  246. package/dist/core/tools/edit.js +24 -0
  247. package/dist/core/tools/edit.js.map +1 -1
  248. package/dist/core/tools/find.d.ts +2 -2
  249. package/dist/core/tools/find.d.ts.map +1 -1
  250. package/dist/core/tools/find.js +12 -0
  251. package/dist/core/tools/find.js.map +1 -1
  252. package/dist/core/tools/grep.d.ts +2 -2
  253. package/dist/core/tools/grep.d.ts.map +1 -1
  254. package/dist/core/tools/grep.js +12 -0
  255. package/dist/core/tools/grep.js.map +1 -1
  256. package/dist/core/tools/index.d.ts +29 -4
  257. package/dist/core/tools/index.d.ts.map +1 -1
  258. package/dist/core/tools/index.js +118 -2
  259. package/dist/core/tools/index.js.map +1 -1
  260. package/dist/core/tools/ls.d.ts +2 -2
  261. package/dist/core/tools/ls.d.ts.map +1 -1
  262. package/dist/core/tools/ls.js +12 -0
  263. package/dist/core/tools/ls.js.map +1 -1
  264. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  265. package/dist/core/tools/output-accumulator.js +1 -1
  266. package/dist/core/tools/output-accumulator.js.map +1 -1
  267. package/dist/core/tools/path-permission.d.ts +18 -0
  268. package/dist/core/tools/path-permission.d.ts.map +1 -0
  269. package/dist/core/tools/path-permission.js +28 -0
  270. package/dist/core/tools/path-permission.js.map +1 -0
  271. package/dist/core/tools/plan-present.d.ts +27 -0
  272. package/dist/core/tools/plan-present.d.ts.map +1 -0
  273. package/dist/core/tools/plan-present.js +55 -0
  274. package/dist/core/tools/plan-present.js.map +1 -0
  275. package/dist/core/tools/read.d.ts +2 -2
  276. package/dist/core/tools/read.d.ts.map +1 -1
  277. package/dist/core/tools/read.js +12 -0
  278. package/dist/core/tools/read.js.map +1 -1
  279. package/dist/core/tools/test.d.ts +34 -0
  280. package/dist/core/tools/test.d.ts.map +1 -0
  281. package/dist/core/tools/test.js +75 -0
  282. package/dist/core/tools/test.js.map +1 -0
  283. package/dist/core/tools/todo-write.d.ts +31 -0
  284. package/dist/core/tools/todo-write.d.ts.map +1 -0
  285. package/dist/core/tools/todo-write.js +51 -0
  286. package/dist/core/tools/todo-write.js.map +1 -0
  287. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -2
  288. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  289. package/dist/core/tools/tool-definition-wrapper.js +11 -1
  290. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  291. package/dist/core/tools/tool-schema.d.ts +22 -0
  292. package/dist/core/tools/tool-schema.d.ts.map +1 -0
  293. package/dist/core/tools/tool-schema.js +45 -0
  294. package/dist/core/tools/tool-schema.js.map +1 -0
  295. package/dist/core/tools/web-fetch.d.ts +26 -0
  296. package/dist/core/tools/web-fetch.d.ts.map +1 -0
  297. package/dist/core/tools/web-fetch.js +62 -0
  298. package/dist/core/tools/web-fetch.js.map +1 -0
  299. package/dist/core/tools/web-search.d.ts +26 -0
  300. package/dist/core/tools/web-search.d.ts.map +1 -0
  301. package/dist/core/tools/web-search.js +53 -0
  302. package/dist/core/tools/web-search.js.map +1 -0
  303. package/dist/core/tools/write.d.ts +6 -2
  304. package/dist/core/tools/write.d.ts.map +1 -1
  305. package/dist/core/tools/write.js +32 -1
  306. package/dist/core/tools/write.js.map +1 -1
  307. package/dist/core/usage-performance-store.d.ts +56 -0
  308. package/dist/core/usage-performance-store.d.ts.map +1 -0
  309. package/dist/core/usage-performance-store.js +85 -0
  310. package/dist/core/usage-performance-store.js.map +1 -0
  311. package/dist/index.d.ts +1 -0
  312. package/dist/index.d.ts.map +1 -1
  313. package/dist/index.js +1 -0
  314. package/dist/index.js.map +1 -1
  315. package/dist/main.d.ts.map +1 -1
  316. package/dist/main.js +48 -6
  317. package/dist/main.js.map +1 -1
  318. package/dist/migrations.d.ts.map +1 -1
  319. package/dist/migrations.js +2 -2
  320. package/dist/migrations.js.map +1 -1
  321. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  322. package/dist/modes/interactive/components/config-selector.js +9 -6
  323. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  324. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -4
  325. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/first-time-setup.js +11 -39
  327. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  328. package/dist/modes/interactive/components/footer.d.ts +8 -1
  329. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/footer.js +49 -20
  331. package/dist/modes/interactive/components/footer.js.map +1 -1
  332. package/dist/modes/interactive/components/settings-selector.d.ts +2 -2
  333. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/settings-selector.js +6 -6
  335. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  336. package/dist/modes/interactive/components/tool-execution.d.ts +2 -1
  337. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  339. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  340. package/dist/modes/interactive/external-editor.js +58 -9
  341. package/dist/modes/interactive/external-editor.js.map +1 -1
  342. package/dist/modes/interactive/interactive-mode.d.ts +2 -3
  343. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  344. package/dist/modes/interactive/interactive-mode.js +92 -104
  345. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  346. package/dist/modes/interactive/theme/theme-schema.json +2 -2
  347. package/dist/package-manager-cli.d.ts.map +1 -1
  348. package/dist/package-manager-cli.js +15 -10
  349. package/dist/package-manager-cli.js.map +1 -1
  350. package/dist/rpc-entry.d.ts.map +1 -1
  351. package/dist/rpc-entry.js +2 -1
  352. package/dist/rpc-entry.js.map +1 -1
  353. package/dist/server/create-harness.d.ts +1 -1
  354. package/dist/server/create-harness.d.ts.map +1 -1
  355. package/dist/server/create-harness.js +6 -5
  356. package/dist/server/create-harness.js.map +1 -1
  357. package/dist/testing/replay/metrics.d.ts +24 -0
  358. package/dist/testing/replay/metrics.d.ts.map +1 -0
  359. package/dist/testing/replay/metrics.js +35 -0
  360. package/dist/testing/replay/metrics.js.map +1 -0
  361. package/dist/testing/replay/recorded-provider.d.ts +10 -0
  362. package/dist/testing/replay/recorded-provider.d.ts.map +1 -0
  363. package/dist/testing/replay/recorded-provider.js +108 -0
  364. package/dist/testing/replay/recorded-provider.js.map +1 -0
  365. package/dist/testing/replay/runner.d.ts +56 -0
  366. package/dist/testing/replay/runner.d.ts.map +1 -0
  367. package/dist/testing/replay/runner.js +406 -0
  368. package/dist/testing/replay/runner.js.map +1 -0
  369. package/dist/utils/apex-code-user-agent.d.ts +2 -0
  370. package/dist/utils/apex-code-user-agent.d.ts.map +1 -0
  371. package/dist/utils/apex-code-user-agent.js +5 -0
  372. package/dist/utils/apex-code-user-agent.js.map +1 -0
  373. package/dist/utils/clipboard-image.d.ts.map +1 -1
  374. package/dist/utils/clipboard-image.js +1 -1
  375. package/dist/utils/clipboard-image.js.map +1 -1
  376. package/dist/utils/tools-manager.d.ts +32 -0
  377. package/dist/utils/tools-manager.d.ts.map +1 -1
  378. package/dist/utils/tools-manager.js +198 -100
  379. package/dist/utils/tools-manager.js.map +1 -1
  380. package/dist/utils/version-check.d.ts +5 -5
  381. package/dist/utils/version-check.d.ts.map +1 -1
  382. package/dist/utils/version-check.js +23 -14
  383. package/dist/utils/version-check.js.map +1 -1
  384. package/dist/utils/windows-self-update.d.ts.map +1 -1
  385. package/dist/utils/windows-self-update.js +1 -1
  386. package/dist/utils/windows-self-update.js.map +1 -1
  387. package/docs/compaction.md +21 -21
  388. package/docs/containerization.md +24 -21
  389. package/docs/custom-provider.md +9 -9
  390. package/docs/development.md +11 -11
  391. package/docs/environment-variables.md +36 -77
  392. package/docs/extensions.md +47 -47
  393. package/docs/index.md +12 -24
  394. package/docs/json.md +6 -6
  395. package/docs/keybindings.md +3 -3
  396. package/docs/llama-cpp.md +7 -7
  397. package/docs/models.md +11 -11
  398. package/docs/packages.md +46 -42
  399. package/docs/prompt-templates.md +3 -3
  400. package/docs/providers.md +10 -10
  401. package/docs/quickstart.md +49 -32
  402. package/docs/rpc.md +11 -11
  403. package/docs/sdk.md +4 -4
  404. package/docs/security.md +18 -18
  405. package/docs/session-format.md +9 -9
  406. package/docs/sessions.md +13 -13
  407. package/docs/settings.md +10 -14
  408. package/docs/shell-aliases.md +1 -1
  409. package/docs/skills.md +8 -8
  410. package/docs/terminal-setup.md +12 -12
  411. package/docs/termux.md +4 -4
  412. package/docs/themes.md +8 -8
  413. package/docs/tmux.md +4 -4
  414. package/docs/tui.md +3 -3
  415. package/docs/usage.md +54 -51
  416. package/docs/windows.md +1 -1
  417. package/npm-shrinkwrap.json +5 -5
  418. package/package.json +2 -3
  419. package/dist/core/telemetry.d.ts +0 -3
  420. package/dist/core/telemetry.d.ts.map +0 -1
  421. package/dist/core/telemetry.js +0 -9
  422. package/dist/core/telemetry.js.map +0 -1
  423. package/dist/utils/pi-user-agent.d.ts +0 -2
  424. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  425. package/dist/utils/pi-user-agent.js +0 -5
  426. package/dist/utils/pi-user-agent.js.map +0 -1
@@ -0,0 +1,62 @@
1
+ import { readGitProvenance } from "./provenance.js";
2
+ import { openDurableStateStore, } from "./sqlite.js";
3
+ /**
4
+ * Local daemon state coordinator. All session mutations are admitted through a
5
+ * durable lease and journaled before the caller receives its operation callback.
6
+ */
7
+ export class DurableStateDaemon {
8
+ recoveryDiagnostics;
9
+ provenance;
10
+ #store;
11
+ #attachments = new Map();
12
+ constructor(options) {
13
+ this.#store = openDurableStateStore(options.databasePath);
14
+ this.provenance = readGitProvenance(options.cwd ?? process.cwd());
15
+ this.recoveryDiagnostics = this.#store.recoverUnfinishedCommandsWithDiagnostics(`daemon ${options.daemonId} started before command completion`);
16
+ }
17
+ attach(input) {
18
+ const lease = this.#store.acquireLease({
19
+ sessionId: input.sessionId,
20
+ ownerId: input.clientId,
21
+ mode: input.mode,
22
+ ttlMs: input.ttlMs,
23
+ });
24
+ const clients = this.#attachments.get(input.sessionId) ?? new Map();
25
+ clients.set(input.clientId, lease);
26
+ this.#attachments.set(input.sessionId, clients);
27
+ return lease;
28
+ }
29
+ detach(sessionId, clientId) {
30
+ this.#store.releaseLease(sessionId, clientId);
31
+ const clients = this.#attachments.get(sessionId);
32
+ if (!clients)
33
+ return;
34
+ clients.delete(clientId);
35
+ if (clients.size === 0)
36
+ this.#attachments.delete(sessionId);
37
+ }
38
+ beginMutation(input) {
39
+ this.#requireExclusiveAttachment(input.sessionId, input.clientId);
40
+ return this.#store.beginCommand({ id: input.id, sessionId: input.sessionId, command: input.command });
41
+ }
42
+ async runMutation(input, operation) {
43
+ this.#requireExclusiveAttachment(input.sessionId, input.clientId);
44
+ return this.#store.runCommand({ id: input.id, sessionId: input.sessionId, command: input.command }, operation);
45
+ }
46
+ getCommand(id) {
47
+ return this.#store.getCommand(id);
48
+ }
49
+ getCommandCount() {
50
+ return this.#store.commandCount();
51
+ }
52
+ dispose() {
53
+ this.#store.close();
54
+ }
55
+ #requireExclusiveAttachment(sessionId, clientId) {
56
+ const attachment = this.#attachments.get(sessionId)?.get(clientId);
57
+ if (!attachment || attachment.mode !== "exclusive" || Date.parse(attachment.expiresAt) <= Date.now()) {
58
+ throw new Error(`Client does not hold an active exclusive lease for ${sessionId}`);
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/core/durable-state/daemon.ts"],"names":[],"mappings":"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","sourcesContent":["import { type GitProvenance, readGitProvenance } from \"./provenance.ts\";\nimport {\n\ttype CommandJournalRecord,\n\ttype DurableStateStore,\n\topenDurableStateStore,\n\ttype RecoveryDiagnostic,\n\ttype SessionLeaseMode,\n\ttype SessionLeaseRecord,\n} from \"./sqlite.ts\";\n\nexport interface DurableStateDaemonOptions {\n\tdatabasePath: string;\n\tdaemonId: string;\n\tcwd?: string;\n}\nexport interface AttachClientInput {\n\tsessionId: string;\n\tclientId: string;\n\tmode: SessionLeaseMode;\n\tttlMs: number;\n}\nexport interface MutationInput {\n\tid?: string;\n\tsessionId: string;\n\tclientId: string;\n\tcommand: string;\n}\n\n/**\n * Local daemon state coordinator. All session mutations are admitted through a\n * durable lease and journaled before the caller receives its operation callback.\n */\nexport class DurableStateDaemon {\n\treadonly recoveryDiagnostics: readonly RecoveryDiagnostic[];\n\treadonly provenance: GitProvenance;\n\treadonly #store: DurableStateStore;\n\treadonly #attachments = new Map<string, Map<string, SessionLeaseRecord>>();\n\n\tconstructor(options: DurableStateDaemonOptions) {\n\t\tthis.#store = openDurableStateStore(options.databasePath);\n\t\tthis.provenance = readGitProvenance(options.cwd ?? process.cwd());\n\t\tthis.recoveryDiagnostics = this.#store.recoverUnfinishedCommandsWithDiagnostics(\n\t\t\t`daemon ${options.daemonId} started before command completion`,\n\t\t);\n\t}\n\n\tattach(input: AttachClientInput): SessionLeaseRecord {\n\t\tconst lease = this.#store.acquireLease({\n\t\t\tsessionId: input.sessionId,\n\t\t\townerId: input.clientId,\n\t\t\tmode: input.mode,\n\t\t\tttlMs: input.ttlMs,\n\t\t});\n\t\tconst clients = this.#attachments.get(input.sessionId) ?? new Map<string, SessionLeaseRecord>();\n\t\tclients.set(input.clientId, lease);\n\t\tthis.#attachments.set(input.sessionId, clients);\n\t\treturn lease;\n\t}\n\n\tdetach(sessionId: string, clientId: string): void {\n\t\tthis.#store.releaseLease(sessionId, clientId);\n\t\tconst clients = this.#attachments.get(sessionId);\n\t\tif (!clients) return;\n\t\tclients.delete(clientId);\n\t\tif (clients.size === 0) this.#attachments.delete(sessionId);\n\t}\n\n\tbeginMutation(input: MutationInput): CommandJournalRecord {\n\t\tthis.#requireExclusiveAttachment(input.sessionId, input.clientId);\n\t\treturn this.#store.beginCommand({ id: input.id, sessionId: input.sessionId, command: input.command });\n\t}\n\n\tasync runMutation<T>(input: MutationInput, operation: () => Promise<T>): Promise<T> {\n\t\tthis.#requireExclusiveAttachment(input.sessionId, input.clientId);\n\t\treturn this.#store.runCommand({ id: input.id, sessionId: input.sessionId, command: input.command }, operation);\n\t}\n\n\tgetCommand(id: string): CommandJournalRecord | undefined {\n\t\treturn this.#store.getCommand(id);\n\t}\n\tgetCommandCount(): number {\n\t\treturn this.#store.commandCount();\n\t}\n\tdispose(): void {\n\t\tthis.#store.close();\n\t}\n\n\t#requireExclusiveAttachment(sessionId: string, clientId: string): void {\n\t\tconst attachment = this.#attachments.get(sessionId)?.get(clientId);\n\t\tif (!attachment || attachment.mode !== \"exclusive\" || Date.parse(attachment.expiresAt) <= Date.now()) {\n\t\t\tthrow new Error(`Client does not hold an active exclusive lease for ${sessionId}`);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export interface GitProvenance {
2
+ repositoryRoot?: string;
3
+ revision?: string;
4
+ dirty?: boolean;
5
+ }
6
+ export declare function readGitProvenance(cwd: string): GitProvenance;
7
+ //# sourceMappingURL=provenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../../src/core/durable-state/provenance.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAoB5D","sourcesContent":["import { spawnProcessSync } from \"../../utils/child-process.ts\";\n\nexport interface GitProvenance {\n\trepositoryRoot?: string;\n\trevision?: string;\n\tdirty?: boolean;\n}\n\nexport function readGitProvenance(cwd: string): GitProvenance {\n\tconst root = spawnProcessSync(\"git\", [\"-C\", cwd, \"rev-parse\", \"--show-toplevel\"], {\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tif (root.status !== 0 || !root.stdout.trim()) return {};\n\tconst repositoryRoot = root.stdout.trim();\n\tconst revision = spawnProcessSync(\"git\", [\"-C\", repositoryRoot, \"rev-parse\", \"HEAD\"], {\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tconst dirty = spawnProcessSync(\"git\", [\"-C\", repositoryRoot, \"status\", \"--porcelain\"], {\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\treturn {\n\t\trepositoryRoot,\n\t\t...(revision.status === 0 && revision.stdout.trim() ? { revision: revision.stdout.trim() } : {}),\n\t\t...(dirty.status === 0 ? { dirty: Boolean(dirty.stdout.trim()) } : {}),\n\t};\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { spawnProcessSync } from "../../utils/child-process.js";
2
+ export function readGitProvenance(cwd) {
3
+ const root = spawnProcessSync("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
4
+ encoding: "utf8",
5
+ stdio: ["ignore", "pipe", "ignore"],
6
+ });
7
+ if (root.status !== 0 || !root.stdout.trim())
8
+ return {};
9
+ const repositoryRoot = root.stdout.trim();
10
+ const revision = spawnProcessSync("git", ["-C", repositoryRoot, "rev-parse", "HEAD"], {
11
+ encoding: "utf8",
12
+ stdio: ["ignore", "pipe", "ignore"],
13
+ });
14
+ const dirty = spawnProcessSync("git", ["-C", repositoryRoot, "status", "--porcelain"], {
15
+ encoding: "utf8",
16
+ stdio: ["ignore", "pipe", "ignore"],
17
+ });
18
+ return {
19
+ repositoryRoot,
20
+ ...(revision.status === 0 && revision.stdout.trim() ? { revision: revision.stdout.trim() } : {}),
21
+ ...(dirty.status === 0 ? { dirty: Boolean(dirty.stdout.trim()) } : {}),
22
+ };
23
+ }
24
+ //# sourceMappingURL=provenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provenance.js","sourceRoot":"","sources":["../../../src/core/durable-state/provenance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAQhE,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAiB;IAC7D,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,iBAAiB,CAAC,EAAE;QACjF,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;KACnC,CAAC,CAAC;IACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IACxD,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE;QACrF,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;KACnC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE;QACtF,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;KACnC,CAAC,CAAC;IACH,OAAO;QACN,cAAc;QACd,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChG,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtE,CAAC;AAAA,CACF","sourcesContent":["import { spawnProcessSync } from \"../../utils/child-process.ts\";\n\nexport interface GitProvenance {\n\trepositoryRoot?: string;\n\trevision?: string;\n\tdirty?: boolean;\n}\n\nexport function readGitProvenance(cwd: string): GitProvenance {\n\tconst root = spawnProcessSync(\"git\", [\"-C\", cwd, \"rev-parse\", \"--show-toplevel\"], {\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tif (root.status !== 0 || !root.stdout.trim()) return {};\n\tconst repositoryRoot = root.stdout.trim();\n\tconst revision = spawnProcessSync(\"git\", [\"-C\", repositoryRoot, \"rev-parse\", \"HEAD\"], {\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\tconst dirty = spawnProcessSync(\"git\", [\"-C\", repositoryRoot, \"status\", \"--porcelain\"], {\n\t\tencoding: \"utf8\",\n\t\tstdio: [\"ignore\", \"pipe\", \"ignore\"],\n\t});\n\treturn {\n\t\trepositoryRoot,\n\t\t...(revision.status === 0 && revision.stdout.trim() ? { revision: revision.stdout.trim() } : {}),\n\t\t...(dirty.status === 0 ? { dirty: Boolean(dirty.stdout.trim()) } : {}),\n\t};\n}\n"]}
@@ -0,0 +1,84 @@
1
+ /** Current schema for the daemon-owned durable-state sidecar. */
2
+ export declare const CURRENT_DURABLE_STATE_SCHEMA_VERSION = 4;
3
+ export type CommandJournalState = "created" | "running" | "completed" | "failed" | "interrupted";
4
+ export type SessionLeaseMode = "shared" | "exclusive";
5
+ export interface SessionLeaseRecord {
6
+ sessionId: string;
7
+ ownerId: string;
8
+ mode: SessionLeaseMode;
9
+ expiresAt: string;
10
+ }
11
+ export interface CommandJournalRecord {
12
+ id: string;
13
+ sessionId: string;
14
+ command: string;
15
+ state: CommandJournalState;
16
+ createdAt: string;
17
+ updatedAt: string;
18
+ recoveryReason?: string;
19
+ }
20
+ /**
21
+ * Plain, domain-independent row shape for `model_performance`. Deliberately not the
22
+ * richer `UsagePerformanceSample` (which carries a branded `CredentialIdentity` and a
23
+ * nested `usage` object) — this module owns SQLite schema and writes only, never
24
+ * `ModelRuntime`'s domain types, to avoid a circular import between the two.
25
+ */
26
+ export interface UsagePerformanceRow {
27
+ provider: string;
28
+ modelId: string;
29
+ ttftMs: number | null;
30
+ generationMs: number | null;
31
+ sampledAt: string;
32
+ sessionId: string | null;
33
+ role: string | null;
34
+ credentialIdentity: string | null;
35
+ outcome: string | null;
36
+ failureKind: string | null;
37
+ inputTokens: number | null;
38
+ outputTokens: number | null;
39
+ cacheReadTokens: number | null;
40
+ cacheWriteTokens: number | null;
41
+ cost: number | null;
42
+ }
43
+ export interface RecoveryDiagnostic {
44
+ commandId: string;
45
+ sessionId: string;
46
+ previousState: "created" | "running";
47
+ state: "interrupted";
48
+ reason: string;
49
+ recoveredAt: string;
50
+ }
51
+ export interface DurableStateStore {
52
+ schemaVersion(): number;
53
+ tableNames(): string[];
54
+ columns(tableName: string): string[];
55
+ beginCommand(input: {
56
+ id?: string;
57
+ sessionId: string;
58
+ command: string;
59
+ }): CommandJournalRecord;
60
+ runCommand<T>(input: {
61
+ id?: string;
62
+ sessionId: string;
63
+ command: string;
64
+ }, operation: () => Promise<T>): Promise<T>;
65
+ transitionCommand(id: string, state: Exclude<CommandJournalState, "created">, reason?: string): CommandJournalRecord;
66
+ getCommand(id: string): CommandJournalRecord | undefined;
67
+ commandCount(): number;
68
+ recoverUnfinishedCommands(reason?: string): CommandJournalRecord[];
69
+ recoverUnfinishedCommandsWithDiagnostics(reason?: string): RecoveryDiagnostic[];
70
+ acquireLease(input: {
71
+ sessionId: string;
72
+ ownerId: string;
73
+ mode: SessionLeaseMode;
74
+ ttlMs: number;
75
+ }): SessionLeaseRecord;
76
+ releaseLease(sessionId: string, ownerId: string): void;
77
+ getLease(sessionId: string): SessionLeaseRecord | undefined;
78
+ recordUsagePerformance(row: UsagePerformanceRow): void;
79
+ listUsagePerformance(): UsagePerformanceRow[];
80
+ pruneUsagePerformance(olderThanIso: string): number;
81
+ close(): void;
82
+ }
83
+ export declare function openDurableStateStore(path: string): DurableStateStore;
84
+ //# sourceMappingURL=sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/core/durable-state/sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { DatabaseSync } from \"node:sqlite\";\n\n/** Current schema for the daemon-owned durable-state sidecar. */\nexport const CURRENT_DURABLE_STATE_SCHEMA_VERSION = 4;\n\nexport type CommandJournalState = \"created\" | \"running\" | \"completed\" | \"failed\" | \"interrupted\";\n\nexport type SessionLeaseMode = \"shared\" | \"exclusive\";\nexport interface SessionLeaseRecord {\n\tsessionId: string;\n\townerId: string;\n\tmode: SessionLeaseMode;\n\texpiresAt: string;\n}\n\nexport interface CommandJournalRecord {\n\tid: string;\n\tsessionId: string;\n\tcommand: string;\n\tstate: CommandJournalState;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\trecoveryReason?: string;\n}\n\nconst COMMAND_TRANSITIONS: Record<CommandJournalState, readonly CommandJournalState[]> = {\n\tcreated: [\"running\", \"failed\", \"interrupted\"],\n\trunning: [\"completed\", \"failed\", \"interrupted\"],\n\tcompleted: [],\n\tfailed: [],\n\tinterrupted: [],\n};\n\nconst TABLES = [\n\t\"cache_entries\",\n\t\"command_journal\",\n\t\"daemon_metadata\",\n\t\"model_performance\",\n\t\"schema_migrations\",\n\t\"session_leases\",\n] as const;\n\n/** Columns added to `model_performance` in schema version 4 (roadmap Phase 8). */\nconst MODEL_PERFORMANCE_V4_COLUMNS: ReadonlyArray<readonly [string, string]> = [\n\t[\"session_id\", \"TEXT\"],\n\t[\"role\", \"TEXT\"],\n\t[\"credential_identity\", \"TEXT\"],\n\t[\"outcome\", \"TEXT\"],\n\t[\"failure_kind\", \"TEXT\"],\n\t[\"input_tokens\", \"INTEGER\"],\n\t[\"output_tokens\", \"INTEGER\"],\n\t[\"cache_read_tokens\", \"INTEGER\"],\n\t[\"cache_write_tokens\", \"INTEGER\"],\n\t[\"cost\", \"REAL\"],\n];\n\n/**\n * Plain, domain-independent row shape for `model_performance`. Deliberately not the\n * richer `UsagePerformanceSample` (which carries a branded `CredentialIdentity` and a\n * nested `usage` object) — this module owns SQLite schema and writes only, never\n * `ModelRuntime`'s domain types, to avoid a circular import between the two.\n */\nexport interface UsagePerformanceRow {\n\tprovider: string;\n\tmodelId: string;\n\tttftMs: number | null;\n\tgenerationMs: number | null;\n\tsampledAt: string;\n\tsessionId: string | null;\n\trole: string | null;\n\tcredentialIdentity: string | null;\n\toutcome: string | null;\n\tfailureKind: string | null;\n\tinputTokens: number | null;\n\toutputTokens: number | null;\n\tcacheReadTokens: number | null;\n\tcacheWriteTokens: number | null;\n\tcost: number | null;\n}\n\nexport interface RecoveryDiagnostic {\n\tcommandId: string;\n\tsessionId: string;\n\tpreviousState: \"created\" | \"running\";\n\tstate: \"interrupted\";\n\treason: string;\n\trecoveredAt: string;\n}\n\nexport interface DurableStateStore {\n\tschemaVersion(): number;\n\ttableNames(): string[];\n\tcolumns(tableName: string): string[];\n\tbeginCommand(input: { id?: string; sessionId: string; command: string }): CommandJournalRecord;\n\trunCommand<T>(input: { id?: string; sessionId: string; command: string }, operation: () => Promise<T>): Promise<T>;\n\ttransitionCommand(id: string, state: Exclude<CommandJournalState, \"created\">, reason?: string): CommandJournalRecord;\n\tgetCommand(id: string): CommandJournalRecord | undefined;\n\tcommandCount(): number;\n\trecoverUnfinishedCommands(reason?: string): CommandJournalRecord[];\n\trecoverUnfinishedCommandsWithDiagnostics(reason?: string): RecoveryDiagnostic[];\n\tacquireLease(input: {\n\t\tsessionId: string;\n\t\townerId: string;\n\t\tmode: SessionLeaseMode;\n\t\tttlMs: number;\n\t}): SessionLeaseRecord;\n\treleaseLease(sessionId: string, ownerId: string): void;\n\tgetLease(sessionId: string): SessionLeaseRecord | undefined;\n\trecordUsagePerformance(row: UsagePerformanceRow): void;\n\tlistUsagePerformance(): UsagePerformanceRow[];\n\tpruneUsagePerformance(olderThanIso: string): number;\n\tclose(): void;\n}\n\nfunction readSchemaVersion(database: DatabaseSync): number {\n\tconst row = database.prepare(\"SELECT COALESCE(MAX(version), 0) AS version FROM schema_migrations\").get() as\n\t\t| { version: number }\n\t\t| undefined;\n\treturn row?.version ?? 0;\n}\n\nfunction createSchema(database: DatabaseSync): void {\n\tdatabase.exec(`\n\t\tCREATE TABLE IF NOT EXISTS schema_migrations (\n\t\t\tversion INTEGER PRIMARY KEY,\n\t\t\tapplied_at TEXT NOT NULL\n\t\t);\n\t\tCREATE TABLE IF NOT EXISTS daemon_metadata (\n\t\t\tkey TEXT PRIMARY KEY,\n\t\t\tvalue TEXT NOT NULL\n\t\t);\n\t\tCREATE TABLE IF NOT EXISTS command_journal (\n\t\t\tid TEXT PRIMARY KEY,\n\t\t\tsession_id TEXT NOT NULL,\n\t\t\tcommand TEXT NOT NULL,\n\t\t\tstate TEXT NOT NULL,\n\t\t\trecovery_reason TEXT,\n\t\t\tcreated_at TEXT NOT NULL,\n\t\t\tupdated_at TEXT NOT NULL\n\t\t);\n\t\tCREATE TABLE IF NOT EXISTS session_leases (\n\t\t\tsession_id TEXT NOT NULL,\n\t\t\towner_id TEXT NOT NULL,\n\t\t\tmode TEXT NOT NULL,\n\t\t\texpires_at TEXT NOT NULL,\n\t\t\tPRIMARY KEY (session_id, owner_id)\n\t\t);\n\t\tCREATE TABLE IF NOT EXISTS model_performance (\n\t\t\tid INTEGER PRIMARY KEY,\n\t\t\tprovider TEXT NOT NULL,\n\t\t\tmodel_id TEXT NOT NULL,\n\t\t\tttft_ms REAL,\n\t\t\tgeneration_ms REAL,\n\t\t\tsampled_at TEXT NOT NULL,\n\t\t\tsession_id TEXT,\n\t\t\trole TEXT,\n\t\t\tcredential_identity TEXT,\n\t\t\toutcome TEXT,\n\t\t\tfailure_kind TEXT,\n\t\t\tinput_tokens INTEGER,\n\t\t\toutput_tokens INTEGER,\n\t\t\tcache_read_tokens INTEGER,\n\t\t\tcache_write_tokens INTEGER,\n\t\t\tcost REAL\n\t\t);\n\t\tCREATE TABLE IF NOT EXISTS cache_entries (\n\t\t\tkey TEXT PRIMARY KEY,\n\t\t\tvalue BLOB NOT NULL,\n\t\t\texpires_at TEXT\n\t\t);\n\t`);\n}\n\nfunction readCommand(database: DatabaseSync, id: string): CommandJournalRecord | undefined {\n\tconst row = database\n\t\t.prepare(\n\t\t\t\"SELECT id, session_id, command, state, recovery_reason, created_at, updated_at FROM command_journal WHERE id = ?\",\n\t\t)\n\t\t.get(id) as\n\t\t| {\n\t\t\t\tid: string;\n\t\t\t\tsession_id: string;\n\t\t\t\tcommand: string;\n\t\t\t\tstate: CommandJournalState;\n\t\t\t\trecovery_reason: string | null;\n\t\t\t\tcreated_at: string;\n\t\t\t\tupdated_at: string;\n\t\t }\n\t\t| undefined;\n\tif (!row) return undefined;\n\treturn {\n\t\tid: row.id,\n\t\tsessionId: row.session_id,\n\t\tcommand: row.command,\n\t\tstate: row.state,\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t\t...(row.recovery_reason ? { recoveryReason: row.recovery_reason } : {}),\n\t};\n}\n\nfunction readLeases(database: DatabaseSync, sessionId: string): SessionLeaseRecord[] {\n\tconst rows = database\n\t\t.prepare(\n\t\t\t\"SELECT session_id, owner_id, mode, expires_at FROM session_leases WHERE session_id = ? ORDER BY owner_id\",\n\t\t)\n\t\t.all(sessionId) as Array<{ session_id: string; owner_id: string; mode: SessionLeaseMode; expires_at: string }>;\n\treturn rows.map((row) => ({\n\t\tsessionId: row.session_id,\n\t\townerId: row.owner_id,\n\t\tmode: row.mode,\n\t\texpiresAt: row.expires_at,\n\t}));\n}\n\nfunction readLease(database: DatabaseSync, sessionId: string): SessionLeaseRecord | undefined {\n\treturn readLeases(database, sessionId)[0];\n}\n\nfunction transitionCommand(\n\tdatabase: DatabaseSync,\n\tid: string,\n\tstate: Exclude<CommandJournalState, \"created\">,\n\treason?: string,\n): CommandJournalRecord {\n\tconst current = readCommand(database, id);\n\tif (!current) throw new Error(`Unknown command journal entry: ${id}`);\n\tif (!COMMAND_TRANSITIONS[current.state].includes(state))\n\t\tthrow new Error(`Invalid command transition: ${current.state} -> ${state}`);\n\tconst now = new Date().toISOString();\n\tdatabase\n\t\t.prepare(\"UPDATE command_journal SET state = ?, recovery_reason = ?, updated_at = ? WHERE id = ?\")\n\t\t.run(state, reason ?? null, now, id);\n\treturn readCommand(database, id)!;\n}\n\nexport function openDurableStateStore(path: string): DurableStateStore {\n\tconst database = new DatabaseSync(path);\n\ttry {\n\t\tdatabase.exec(\"BEGIN IMMEDIATE\");\n\t\tcreateSchema(database);\n\t\tconst version = readSchemaVersion(database);\n\t\tif (version > CURRENT_DURABLE_STATE_SCHEMA_VERSION) {\n\t\t\tdatabase.exec(\"ROLLBACK\");\n\t\t\tthrow new Error(\n\t\t\t\t`Durable state database schema version ${version} is newer than this version (${CURRENT_DURABLE_STATE_SCHEMA_VERSION})`,\n\t\t\t);\n\t\t}\n\t\tif (version < 2) {\n\t\t\tconst commandColumns = database.prepare('PRAGMA table_info(\"command_journal\")').all() as Array<{\n\t\t\t\tname: string;\n\t\t\t}>;\n\t\t\tif (!commandColumns.some((column) => column.name === \"recovery_reason\"))\n\t\t\t\tdatabase.exec(\"ALTER TABLE command_journal ADD COLUMN recovery_reason TEXT\");\n\t\t}\n\t\tif (version < 3 && version > 0) {\n\t\t\tdatabase.exec(`\n\t\t\t\tALTER TABLE session_leases RENAME TO session_leases_v2;\n\t\t\t\tCREATE TABLE session_leases (\n\t\t\t\t\tsession_id TEXT NOT NULL,\n\t\t\t\t\towner_id TEXT NOT NULL,\n\t\t\t\t\tmode TEXT NOT NULL,\n\t\t\t\t\texpires_at TEXT NOT NULL,\n\t\t\t\t\tPRIMARY KEY (session_id, owner_id)\n\t\t\t\t);\n\t\t\t\tINSERT INTO session_leases (session_id, owner_id, mode, expires_at)\n\t\t\t\tSELECT session_id, owner_id, mode, expires_at FROM session_leases_v2;\n\t\t\t\tDROP TABLE session_leases_v2;\n\t\t\t`);\n\t\t}\n\t\tif (version < 4 && version > 0) {\n\t\t\tconst modelPerformanceColumns = database.prepare('PRAGMA table_info(\"model_performance\")').all() as Array<{\n\t\t\t\tname: string;\n\t\t\t}>;\n\t\t\tconst existingNames = new Set(modelPerformanceColumns.map((column) => column.name));\n\t\t\tfor (const [name, type] of MODEL_PERFORMANCE_V4_COLUMNS) {\n\t\t\t\tif (!existingNames.has(name)) database.exec(`ALTER TABLE model_performance ADD COLUMN ${name} ${type}`);\n\t\t\t}\n\t\t\tdatabase.exec(\"DROP TABLE IF EXISTS usage_totals\");\n\t\t}\n\t\tif (version < CURRENT_DURABLE_STATE_SCHEMA_VERSION) {\n\t\t\tdatabase\n\t\t\t\t.prepare(\"INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)\")\n\t\t\t\t.run(CURRENT_DURABLE_STATE_SCHEMA_VERSION, new Date().toISOString());\n\t\t}\n\t\tdatabase.exec(\"COMMIT\");\n\t} catch (error) {\n\t\ttry {\n\t\t\tdatabase.exec(\"ROLLBACK\");\n\t\t} catch {\n\t\t\t// Preserve the original migration error.\n\t\t}\n\t\tdatabase.close();\n\t\tthrow error;\n\t}\n\n\treturn {\n\t\tschemaVersion: () => readSchemaVersion(database),\n\t\ttableNames: () => {\n\t\t\tconst rows = database\n\t\t\t\t.prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name\")\n\t\t\t\t.all() as Array<{ name: string }>;\n\t\t\treturn rows.map((row) => row.name);\n\t\t},\n\t\tcolumns: (tableName) => {\n\t\t\tif (!TABLES.includes(tableName as (typeof TABLES)[number]))\n\t\t\t\tthrow new Error(`Unknown durable-state table: ${tableName}`);\n\t\t\tconst rows = database.prepare(`PRAGMA table_info(\"${tableName}\")`).all() as Array<{ name: string }>;\n\t\t\treturn rows.map((row) => row.name);\n\t\t},\n\t\tbeginCommand: ({ id = randomUUID(), sessionId, command }) => {\n\t\t\tconst now = new Date().toISOString();\n\t\t\tdatabase\n\t\t\t\t.prepare(\n\t\t\t\t\t\"INSERT INTO command_journal (id, session_id, command, state, created_at, updated_at) VALUES (?, ?, ?, 'created', ?, ?)\",\n\t\t\t\t)\n\t\t\t\t.run(id, sessionId, command, now, now);\n\t\t\treturn readCommand(database, id)!;\n\t\t},\n\t\trunCommand: async (input, operation) => {\n\t\t\tconst entry = (() => {\n\t\t\t\tconst id = input.id ?? randomUUID();\n\t\t\t\tconst now = new Date().toISOString();\n\t\t\t\tdatabase\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\"INSERT INTO command_journal (id, session_id, command, state, created_at, updated_at) VALUES (?, ?, ?, 'created', ?, ?)\",\n\t\t\t\t\t)\n\t\t\t\t\t.run(id, input.sessionId, input.command, now, now);\n\t\t\t\treturn readCommand(database, id)!;\n\t\t\t})();\n\t\t\ttransitionCommand(database, entry.id, \"running\");\n\t\t\ttry {\n\t\t\t\tconst result = await operation();\n\t\t\t\ttransitionCommand(database, entry.id, \"completed\");\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\ttransitionCommand(database, entry.id, \"failed\");\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\ttransitionCommand: (id, state, reason) => {\n\t\t\tconst current = readCommand(database, id);\n\t\t\tif (!current) throw new Error(`Unknown command journal entry: ${id}`);\n\t\t\tif (!COMMAND_TRANSITIONS[current.state].includes(state))\n\t\t\t\tthrow new Error(`Invalid command transition: ${current.state} -> ${state}`);\n\t\t\tconst now = new Date().toISOString();\n\t\t\tdatabase\n\t\t\t\t.prepare(\"UPDATE command_journal SET state = ?, recovery_reason = ?, updated_at = ? WHERE id = ?\")\n\t\t\t\t.run(state, reason ?? null, now, id);\n\t\t\treturn readCommand(database, id)!;\n\t\t},\n\t\tgetCommand: (id) => readCommand(database, id),\n\t\tcommandCount: () =>\n\t\t\t(database.prepare(\"SELECT COUNT(*) AS count FROM command_journal\").get() as { count: number }).count,\n\t\trecoverUnfinishedCommands: (reason = \"daemon restarted before command completion\") => {\n\t\t\tconst rows = database\n\t\t\t\t.prepare(\"SELECT id FROM command_journal WHERE state IN ('created', 'running')\")\n\t\t\t\t.all() as Array<{ id: string }>;\n\t\t\treturn rows.map(({ id }) => {\n\t\t\t\tconst current = readCommand(database, id)!;\n\t\t\t\treturn current.state === \"interrupted\" ? current : transitionCommand(database, id, \"interrupted\", reason);\n\t\t\t});\n\t\t},\n\t\trecoverUnfinishedCommandsWithDiagnostics: (reason = \"daemon restarted before command completion\") => {\n\t\t\tconst recoveredAt = new Date().toISOString();\n\t\t\tconst rows = database\n\t\t\t\t.prepare(\"SELECT id, session_id, state FROM command_journal WHERE state IN ('created', 'running')\")\n\t\t\t\t.all() as Array<{ id: string; session_id: string; state: \"created\" | \"running\" }>;\n\t\t\treturn rows.map((row) => {\n\t\t\t\ttransitionCommand(database, row.id, \"interrupted\", reason);\n\t\t\t\treturn {\n\t\t\t\t\tcommandId: row.id,\n\t\t\t\t\tsessionId: row.session_id,\n\t\t\t\t\tpreviousState: row.state,\n\t\t\t\t\tstate: \"interrupted\" as const,\n\t\t\t\t\treason,\n\t\t\t\t\trecoveredAt,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\tacquireLease: ({ sessionId, ownerId, mode, ttlMs }) => {\n\t\t\tif (!Number.isFinite(ttlMs) || ttlMs <= 0) throw new Error(\"Lease TTL must be positive\");\n\t\t\tdatabase.exec(\"BEGIN IMMEDIATE\");\n\t\t\ttry {\n\t\t\t\tdatabase.prepare(\"DELETE FROM session_leases WHERE expires_at <= ?\").run(new Date().toISOString());\n\t\t\t\tconst active = readLeases(database, sessionId).filter((lease) => lease.ownerId !== ownerId);\n\t\t\t\tif (active.some((lease) => lease.mode === \"exclusive\") || (mode === \"exclusive\" && active.length > 0)) {\n\t\t\t\t\tthrow new Error(`Session lease is held for ${sessionId}`);\n\t\t\t\t}\n\t\t\t\tconst expiresAt = new Date(Date.now() + ttlMs).toISOString();\n\t\t\t\tdatabase\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\"INSERT INTO session_leases (session_id, owner_id, mode, expires_at) VALUES (?, ?, ?, ?) ON CONFLICT(session_id, owner_id) DO UPDATE SET mode=excluded.mode, expires_at=excluded.expires_at\",\n\t\t\t\t\t)\n\t\t\t\t\t.run(sessionId, ownerId, mode, expiresAt);\n\t\t\t\tdatabase.exec(\"COMMIT\");\n\t\t\t\treturn readLeases(database, sessionId).find((lease) => lease.ownerId === ownerId)!;\n\t\t\t} catch (error) {\n\t\t\t\tdatabase.exec(\"ROLLBACK\");\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\treleaseLease: (sessionId, ownerId) => {\n\t\t\tdatabase.prepare(\"DELETE FROM session_leases WHERE session_id = ? AND owner_id = ?\").run(sessionId, ownerId);\n\t\t},\n\t\tgetLease: (sessionId) => readLease(database, sessionId),\n\t\trecordUsagePerformance: (row) => {\n\t\t\tdatabase\n\t\t\t\t.prepare(\n\t\t\t\t\t`INSERT INTO model_performance (\n\t\t\t\t\t\tprovider, model_id, ttft_ms, generation_ms, sampled_at,\n\t\t\t\t\t\tsession_id, role, credential_identity, outcome, failure_kind,\n\t\t\t\t\t\tinput_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost\n\t\t\t\t\t) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n\t\t\t\t)\n\t\t\t\t.run(\n\t\t\t\t\trow.provider,\n\t\t\t\t\trow.modelId,\n\t\t\t\t\trow.ttftMs,\n\t\t\t\t\trow.generationMs,\n\t\t\t\t\trow.sampledAt,\n\t\t\t\t\trow.sessionId,\n\t\t\t\t\trow.role,\n\t\t\t\t\trow.credentialIdentity,\n\t\t\t\t\trow.outcome,\n\t\t\t\t\trow.failureKind,\n\t\t\t\t\trow.inputTokens,\n\t\t\t\t\trow.outputTokens,\n\t\t\t\t\trow.cacheReadTokens,\n\t\t\t\t\trow.cacheWriteTokens,\n\t\t\t\t\trow.cost,\n\t\t\t\t);\n\t\t},\n\t\tlistUsagePerformance: () =>\n\t\t\t(\n\t\t\t\tdatabase\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`SELECT provider, model_id, ttft_ms, generation_ms, sampled_at, session_id, role,\n\t\t\t\t\t\t\tcredential_identity, outcome, failure_kind, input_tokens, output_tokens,\n\t\t\t\t\t\t\tcache_read_tokens, cache_write_tokens, cost\n\t\t\t\t\t\tFROM model_performance ORDER BY id ASC`,\n\t\t\t\t\t)\n\t\t\t\t\t.all() as Array<{\n\t\t\t\t\tprovider: string;\n\t\t\t\t\tmodel_id: string;\n\t\t\t\t\tttft_ms: number | null;\n\t\t\t\t\tgeneration_ms: number | null;\n\t\t\t\t\tsampled_at: string;\n\t\t\t\t\tsession_id: string | null;\n\t\t\t\t\trole: string | null;\n\t\t\t\t\tcredential_identity: string | null;\n\t\t\t\t\toutcome: string | null;\n\t\t\t\t\tfailure_kind: string | null;\n\t\t\t\t\tinput_tokens: number | null;\n\t\t\t\t\toutput_tokens: number | null;\n\t\t\t\t\tcache_read_tokens: number | null;\n\t\t\t\t\tcache_write_tokens: number | null;\n\t\t\t\t\tcost: number | null;\n\t\t\t\t}>\n\t\t\t).map((row) => ({\n\t\t\t\tprovider: row.provider,\n\t\t\t\tmodelId: row.model_id,\n\t\t\t\tttftMs: row.ttft_ms,\n\t\t\t\tgenerationMs: row.generation_ms,\n\t\t\t\tsampledAt: row.sampled_at,\n\t\t\t\tsessionId: row.session_id,\n\t\t\t\trole: row.role,\n\t\t\t\tcredentialIdentity: row.credential_identity,\n\t\t\t\toutcome: row.outcome,\n\t\t\t\tfailureKind: row.failure_kind,\n\t\t\t\tinputTokens: row.input_tokens,\n\t\t\t\toutputTokens: row.output_tokens,\n\t\t\t\tcacheReadTokens: row.cache_read_tokens,\n\t\t\t\tcacheWriteTokens: row.cache_write_tokens,\n\t\t\t\tcost: row.cost,\n\t\t\t})),\n\t\tpruneUsagePerformance: (olderThanIso) => {\n\t\t\tconst result = database.prepare(\"DELETE FROM model_performance WHERE sampled_at < ?\").run(olderThanIso);\n\t\t\treturn Number(result.changes);\n\t\t},\n\t\tclose: () => database.close(),\n\t};\n}\n"]}
@@ -0,0 +1,331 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { DatabaseSync } from "node:sqlite";
3
+ /** Current schema for the daemon-owned durable-state sidecar. */
4
+ export const CURRENT_DURABLE_STATE_SCHEMA_VERSION = 4;
5
+ const COMMAND_TRANSITIONS = {
6
+ created: ["running", "failed", "interrupted"],
7
+ running: ["completed", "failed", "interrupted"],
8
+ completed: [],
9
+ failed: [],
10
+ interrupted: [],
11
+ };
12
+ const TABLES = [
13
+ "cache_entries",
14
+ "command_journal",
15
+ "daemon_metadata",
16
+ "model_performance",
17
+ "schema_migrations",
18
+ "session_leases",
19
+ ];
20
+ /** Columns added to `model_performance` in schema version 4 (roadmap Phase 8). */
21
+ const MODEL_PERFORMANCE_V4_COLUMNS = [
22
+ ["session_id", "TEXT"],
23
+ ["role", "TEXT"],
24
+ ["credential_identity", "TEXT"],
25
+ ["outcome", "TEXT"],
26
+ ["failure_kind", "TEXT"],
27
+ ["input_tokens", "INTEGER"],
28
+ ["output_tokens", "INTEGER"],
29
+ ["cache_read_tokens", "INTEGER"],
30
+ ["cache_write_tokens", "INTEGER"],
31
+ ["cost", "REAL"],
32
+ ];
33
+ function readSchemaVersion(database) {
34
+ const row = database.prepare("SELECT COALESCE(MAX(version), 0) AS version FROM schema_migrations").get();
35
+ return row?.version ?? 0;
36
+ }
37
+ function createSchema(database) {
38
+ database.exec(`
39
+ CREATE TABLE IF NOT EXISTS schema_migrations (
40
+ version INTEGER PRIMARY KEY,
41
+ applied_at TEXT NOT NULL
42
+ );
43
+ CREATE TABLE IF NOT EXISTS daemon_metadata (
44
+ key TEXT PRIMARY KEY,
45
+ value TEXT NOT NULL
46
+ );
47
+ CREATE TABLE IF NOT EXISTS command_journal (
48
+ id TEXT PRIMARY KEY,
49
+ session_id TEXT NOT NULL,
50
+ command TEXT NOT NULL,
51
+ state TEXT NOT NULL,
52
+ recovery_reason TEXT,
53
+ created_at TEXT NOT NULL,
54
+ updated_at TEXT NOT NULL
55
+ );
56
+ CREATE TABLE IF NOT EXISTS session_leases (
57
+ session_id TEXT NOT NULL,
58
+ owner_id TEXT NOT NULL,
59
+ mode TEXT NOT NULL,
60
+ expires_at TEXT NOT NULL,
61
+ PRIMARY KEY (session_id, owner_id)
62
+ );
63
+ CREATE TABLE IF NOT EXISTS model_performance (
64
+ id INTEGER PRIMARY KEY,
65
+ provider TEXT NOT NULL,
66
+ model_id TEXT NOT NULL,
67
+ ttft_ms REAL,
68
+ generation_ms REAL,
69
+ sampled_at TEXT NOT NULL,
70
+ session_id TEXT,
71
+ role TEXT,
72
+ credential_identity TEXT,
73
+ outcome TEXT,
74
+ failure_kind TEXT,
75
+ input_tokens INTEGER,
76
+ output_tokens INTEGER,
77
+ cache_read_tokens INTEGER,
78
+ cache_write_tokens INTEGER,
79
+ cost REAL
80
+ );
81
+ CREATE TABLE IF NOT EXISTS cache_entries (
82
+ key TEXT PRIMARY KEY,
83
+ value BLOB NOT NULL,
84
+ expires_at TEXT
85
+ );
86
+ `);
87
+ }
88
+ function readCommand(database, id) {
89
+ const row = database
90
+ .prepare("SELECT id, session_id, command, state, recovery_reason, created_at, updated_at FROM command_journal WHERE id = ?")
91
+ .get(id);
92
+ if (!row)
93
+ return undefined;
94
+ return {
95
+ id: row.id,
96
+ sessionId: row.session_id,
97
+ command: row.command,
98
+ state: row.state,
99
+ createdAt: row.created_at,
100
+ updatedAt: row.updated_at,
101
+ ...(row.recovery_reason ? { recoveryReason: row.recovery_reason } : {}),
102
+ };
103
+ }
104
+ function readLeases(database, sessionId) {
105
+ const rows = database
106
+ .prepare("SELECT session_id, owner_id, mode, expires_at FROM session_leases WHERE session_id = ? ORDER BY owner_id")
107
+ .all(sessionId);
108
+ return rows.map((row) => ({
109
+ sessionId: row.session_id,
110
+ ownerId: row.owner_id,
111
+ mode: row.mode,
112
+ expiresAt: row.expires_at,
113
+ }));
114
+ }
115
+ function readLease(database, sessionId) {
116
+ return readLeases(database, sessionId)[0];
117
+ }
118
+ function transitionCommand(database, id, state, reason) {
119
+ const current = readCommand(database, id);
120
+ if (!current)
121
+ throw new Error(`Unknown command journal entry: ${id}`);
122
+ if (!COMMAND_TRANSITIONS[current.state].includes(state))
123
+ throw new Error(`Invalid command transition: ${current.state} -> ${state}`);
124
+ const now = new Date().toISOString();
125
+ database
126
+ .prepare("UPDATE command_journal SET state = ?, recovery_reason = ?, updated_at = ? WHERE id = ?")
127
+ .run(state, reason ?? null, now, id);
128
+ return readCommand(database, id);
129
+ }
130
+ export function openDurableStateStore(path) {
131
+ const database = new DatabaseSync(path);
132
+ try {
133
+ database.exec("BEGIN IMMEDIATE");
134
+ createSchema(database);
135
+ const version = readSchemaVersion(database);
136
+ if (version > CURRENT_DURABLE_STATE_SCHEMA_VERSION) {
137
+ database.exec("ROLLBACK");
138
+ throw new Error(`Durable state database schema version ${version} is newer than this version (${CURRENT_DURABLE_STATE_SCHEMA_VERSION})`);
139
+ }
140
+ if (version < 2) {
141
+ const commandColumns = database.prepare('PRAGMA table_info("command_journal")').all();
142
+ if (!commandColumns.some((column) => column.name === "recovery_reason"))
143
+ database.exec("ALTER TABLE command_journal ADD COLUMN recovery_reason TEXT");
144
+ }
145
+ if (version < 3 && version > 0) {
146
+ database.exec(`
147
+ ALTER TABLE session_leases RENAME TO session_leases_v2;
148
+ CREATE TABLE session_leases (
149
+ session_id TEXT NOT NULL,
150
+ owner_id TEXT NOT NULL,
151
+ mode TEXT NOT NULL,
152
+ expires_at TEXT NOT NULL,
153
+ PRIMARY KEY (session_id, owner_id)
154
+ );
155
+ INSERT INTO session_leases (session_id, owner_id, mode, expires_at)
156
+ SELECT session_id, owner_id, mode, expires_at FROM session_leases_v2;
157
+ DROP TABLE session_leases_v2;
158
+ `);
159
+ }
160
+ if (version < 4 && version > 0) {
161
+ const modelPerformanceColumns = database.prepare('PRAGMA table_info("model_performance")').all();
162
+ const existingNames = new Set(modelPerformanceColumns.map((column) => column.name));
163
+ for (const [name, type] of MODEL_PERFORMANCE_V4_COLUMNS) {
164
+ if (!existingNames.has(name))
165
+ database.exec(`ALTER TABLE model_performance ADD COLUMN ${name} ${type}`);
166
+ }
167
+ database.exec("DROP TABLE IF EXISTS usage_totals");
168
+ }
169
+ if (version < CURRENT_DURABLE_STATE_SCHEMA_VERSION) {
170
+ database
171
+ .prepare("INSERT INTO schema_migrations (version, applied_at) VALUES (?, ?)")
172
+ .run(CURRENT_DURABLE_STATE_SCHEMA_VERSION, new Date().toISOString());
173
+ }
174
+ database.exec("COMMIT");
175
+ }
176
+ catch (error) {
177
+ try {
178
+ database.exec("ROLLBACK");
179
+ }
180
+ catch {
181
+ // Preserve the original migration error.
182
+ }
183
+ database.close();
184
+ throw error;
185
+ }
186
+ return {
187
+ schemaVersion: () => readSchemaVersion(database),
188
+ tableNames: () => {
189
+ const rows = database
190
+ .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name")
191
+ .all();
192
+ return rows.map((row) => row.name);
193
+ },
194
+ columns: (tableName) => {
195
+ if (!TABLES.includes(tableName))
196
+ throw new Error(`Unknown durable-state table: ${tableName}`);
197
+ const rows = database.prepare(`PRAGMA table_info("${tableName}")`).all();
198
+ return rows.map((row) => row.name);
199
+ },
200
+ beginCommand: ({ id = randomUUID(), sessionId, command }) => {
201
+ const now = new Date().toISOString();
202
+ database
203
+ .prepare("INSERT INTO command_journal (id, session_id, command, state, created_at, updated_at) VALUES (?, ?, ?, 'created', ?, ?)")
204
+ .run(id, sessionId, command, now, now);
205
+ return readCommand(database, id);
206
+ },
207
+ runCommand: async (input, operation) => {
208
+ const entry = (() => {
209
+ const id = input.id ?? randomUUID();
210
+ const now = new Date().toISOString();
211
+ database
212
+ .prepare("INSERT INTO command_journal (id, session_id, command, state, created_at, updated_at) VALUES (?, ?, ?, 'created', ?, ?)")
213
+ .run(id, input.sessionId, input.command, now, now);
214
+ return readCommand(database, id);
215
+ })();
216
+ transitionCommand(database, entry.id, "running");
217
+ try {
218
+ const result = await operation();
219
+ transitionCommand(database, entry.id, "completed");
220
+ return result;
221
+ }
222
+ catch (error) {
223
+ transitionCommand(database, entry.id, "failed");
224
+ throw error;
225
+ }
226
+ },
227
+ transitionCommand: (id, state, reason) => {
228
+ const current = readCommand(database, id);
229
+ if (!current)
230
+ throw new Error(`Unknown command journal entry: ${id}`);
231
+ if (!COMMAND_TRANSITIONS[current.state].includes(state))
232
+ throw new Error(`Invalid command transition: ${current.state} -> ${state}`);
233
+ const now = new Date().toISOString();
234
+ database
235
+ .prepare("UPDATE command_journal SET state = ?, recovery_reason = ?, updated_at = ? WHERE id = ?")
236
+ .run(state, reason ?? null, now, id);
237
+ return readCommand(database, id);
238
+ },
239
+ getCommand: (id) => readCommand(database, id),
240
+ commandCount: () => database.prepare("SELECT COUNT(*) AS count FROM command_journal").get().count,
241
+ recoverUnfinishedCommands: (reason = "daemon restarted before command completion") => {
242
+ const rows = database
243
+ .prepare("SELECT id FROM command_journal WHERE state IN ('created', 'running')")
244
+ .all();
245
+ return rows.map(({ id }) => {
246
+ const current = readCommand(database, id);
247
+ return current.state === "interrupted" ? current : transitionCommand(database, id, "interrupted", reason);
248
+ });
249
+ },
250
+ recoverUnfinishedCommandsWithDiagnostics: (reason = "daemon restarted before command completion") => {
251
+ const recoveredAt = new Date().toISOString();
252
+ const rows = database
253
+ .prepare("SELECT id, session_id, state FROM command_journal WHERE state IN ('created', 'running')")
254
+ .all();
255
+ return rows.map((row) => {
256
+ transitionCommand(database, row.id, "interrupted", reason);
257
+ return {
258
+ commandId: row.id,
259
+ sessionId: row.session_id,
260
+ previousState: row.state,
261
+ state: "interrupted",
262
+ reason,
263
+ recoveredAt,
264
+ };
265
+ });
266
+ },
267
+ acquireLease: ({ sessionId, ownerId, mode, ttlMs }) => {
268
+ if (!Number.isFinite(ttlMs) || ttlMs <= 0)
269
+ throw new Error("Lease TTL must be positive");
270
+ database.exec("BEGIN IMMEDIATE");
271
+ try {
272
+ database.prepare("DELETE FROM session_leases WHERE expires_at <= ?").run(new Date().toISOString());
273
+ const active = readLeases(database, sessionId).filter((lease) => lease.ownerId !== ownerId);
274
+ if (active.some((lease) => lease.mode === "exclusive") || (mode === "exclusive" && active.length > 0)) {
275
+ throw new Error(`Session lease is held for ${sessionId}`);
276
+ }
277
+ const expiresAt = new Date(Date.now() + ttlMs).toISOString();
278
+ database
279
+ .prepare("INSERT INTO session_leases (session_id, owner_id, mode, expires_at) VALUES (?, ?, ?, ?) ON CONFLICT(session_id, owner_id) DO UPDATE SET mode=excluded.mode, expires_at=excluded.expires_at")
280
+ .run(sessionId, ownerId, mode, expiresAt);
281
+ database.exec("COMMIT");
282
+ return readLeases(database, sessionId).find((lease) => lease.ownerId === ownerId);
283
+ }
284
+ catch (error) {
285
+ database.exec("ROLLBACK");
286
+ throw error;
287
+ }
288
+ },
289
+ releaseLease: (sessionId, ownerId) => {
290
+ database.prepare("DELETE FROM session_leases WHERE session_id = ? AND owner_id = ?").run(sessionId, ownerId);
291
+ },
292
+ getLease: (sessionId) => readLease(database, sessionId),
293
+ recordUsagePerformance: (row) => {
294
+ database
295
+ .prepare(`INSERT INTO model_performance (
296
+ provider, model_id, ttft_ms, generation_ms, sampled_at,
297
+ session_id, role, credential_identity, outcome, failure_kind,
298
+ input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, cost
299
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
300
+ .run(row.provider, row.modelId, row.ttftMs, row.generationMs, row.sampledAt, row.sessionId, row.role, row.credentialIdentity, row.outcome, row.failureKind, row.inputTokens, row.outputTokens, row.cacheReadTokens, row.cacheWriteTokens, row.cost);
301
+ },
302
+ listUsagePerformance: () => database
303
+ .prepare(`SELECT provider, model_id, ttft_ms, generation_ms, sampled_at, session_id, role,
304
+ credential_identity, outcome, failure_kind, input_tokens, output_tokens,
305
+ cache_read_tokens, cache_write_tokens, cost
306
+ FROM model_performance ORDER BY id ASC`)
307
+ .all().map((row) => ({
308
+ provider: row.provider,
309
+ modelId: row.model_id,
310
+ ttftMs: row.ttft_ms,
311
+ generationMs: row.generation_ms,
312
+ sampledAt: row.sampled_at,
313
+ sessionId: row.session_id,
314
+ role: row.role,
315
+ credentialIdentity: row.credential_identity,
316
+ outcome: row.outcome,
317
+ failureKind: row.failure_kind,
318
+ inputTokens: row.input_tokens,
319
+ outputTokens: row.output_tokens,
320
+ cacheReadTokens: row.cache_read_tokens,
321
+ cacheWriteTokens: row.cache_write_tokens,
322
+ cost: row.cost,
323
+ })),
324
+ pruneUsagePerformance: (olderThanIso) => {
325
+ const result = database.prepare("DELETE FROM model_performance WHERE sampled_at < ?").run(olderThanIso);
326
+ return Number(result.changes);
327
+ },
328
+ close: () => database.close(),
329
+ };
330
+ }
331
+ //# sourceMappingURL=sqlite.js.map