@nghyane/arcane 0.1.0

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 (738) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +12 -0
  3. package/examples/README.md +21 -0
  4. package/examples/custom-tools/README.md +109 -0
  5. package/examples/custom-tools/hello/index.ts +20 -0
  6. package/examples/custom-tools/todo/index.ts +206 -0
  7. package/examples/extensions/README.md +143 -0
  8. package/examples/extensions/api-demo.ts +89 -0
  9. package/examples/extensions/chalk-logger.ts +25 -0
  10. package/examples/extensions/hello.ts +32 -0
  11. package/examples/extensions/pirate.ts +43 -0
  12. package/examples/extensions/plan-mode.ts +550 -0
  13. package/examples/extensions/reload-runtime.ts +37 -0
  14. package/examples/extensions/todo.ts +296 -0
  15. package/examples/extensions/tools.ts +144 -0
  16. package/examples/extensions/with-deps/index.ts +35 -0
  17. package/examples/extensions/with-deps/package-lock.json +31 -0
  18. package/examples/extensions/with-deps/package.json +16 -0
  19. package/examples/hooks/README.md +56 -0
  20. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  21. package/examples/hooks/confirm-destructive.ts +58 -0
  22. package/examples/hooks/custom-compaction.ts +116 -0
  23. package/examples/hooks/dirty-repo-guard.ts +51 -0
  24. package/examples/hooks/file-trigger.ts +40 -0
  25. package/examples/hooks/git-checkpoint.ts +52 -0
  26. package/examples/hooks/handoff.ts +150 -0
  27. package/examples/hooks/permission-gate.ts +33 -0
  28. package/examples/hooks/protected-paths.ts +29 -0
  29. package/examples/hooks/qna.ts +119 -0
  30. package/examples/hooks/status-line.ts +39 -0
  31. package/examples/sdk/01-minimal.ts +21 -0
  32. package/examples/sdk/02-custom-model.ts +49 -0
  33. package/examples/sdk/03-custom-prompt.ts +43 -0
  34. package/examples/sdk/04-skills.ts +43 -0
  35. package/examples/sdk/06-extensions.ts +80 -0
  36. package/examples/sdk/06-hooks.ts +61 -0
  37. package/examples/sdk/07-context-files.ts +35 -0
  38. package/examples/sdk/08-prompt-templates.ts +36 -0
  39. package/examples/sdk/08-slash-commands.ts +41 -0
  40. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  41. package/examples/sdk/11-sessions.ts +47 -0
  42. package/examples/sdk/README.md +150 -0
  43. package/package.json +464 -0
  44. package/scripts/format-prompts.ts +184 -0
  45. package/scripts/generate-docs-index.ts +40 -0
  46. package/scripts/generate-template.ts +32 -0
  47. package/src/bun-imports.d.ts +22 -0
  48. package/src/capability/context-file.ts +39 -0
  49. package/src/capability/extension-module.ts +33 -0
  50. package/src/capability/extension.ts +47 -0
  51. package/src/capability/fs.ts +89 -0
  52. package/src/capability/hook.ts +39 -0
  53. package/src/capability/index.ts +432 -0
  54. package/src/capability/instruction.ts +36 -0
  55. package/src/capability/mcp.ts +60 -0
  56. package/src/capability/prompt.ts +34 -0
  57. package/src/capability/rule.ts +223 -0
  58. package/src/capability/settings.ts +34 -0
  59. package/src/capability/skill.ts +48 -0
  60. package/src/capability/slash-command.ts +39 -0
  61. package/src/capability/ssh.ts +41 -0
  62. package/src/capability/system-prompt.ts +34 -0
  63. package/src/capability/tool.ts +37 -0
  64. package/src/capability/types.ts +156 -0
  65. package/src/cli/args.ts +259 -0
  66. package/src/cli/config-cli.ts +357 -0
  67. package/src/cli/file-processor.ts +124 -0
  68. package/src/cli/grep-cli.ts +152 -0
  69. package/src/cli/jupyter-cli.ts +106 -0
  70. package/src/cli/list-models.ts +103 -0
  71. package/src/cli/plugin-cli.ts +661 -0
  72. package/src/cli/session-picker.ts +42 -0
  73. package/src/cli/setup-cli.ts +376 -0
  74. package/src/cli/shell-cli.ts +174 -0
  75. package/src/cli/ssh-cli.ts +179 -0
  76. package/src/cli/stats-cli.ts +197 -0
  77. package/src/cli/update-cli.ts +286 -0
  78. package/src/cli/web-search-cli.ts +143 -0
  79. package/src/cli.ts +65 -0
  80. package/src/commands/commit.ts +36 -0
  81. package/src/commands/config.ts +51 -0
  82. package/src/commands/grep.ts +41 -0
  83. package/src/commands/jupyter.ts +32 -0
  84. package/src/commands/launch.ts +139 -0
  85. package/src/commands/plugin.ts +70 -0
  86. package/src/commands/setup.ts +42 -0
  87. package/src/commands/shell.ts +29 -0
  88. package/src/commands/ssh.ts +60 -0
  89. package/src/commands/stats.ts +29 -0
  90. package/src/commands/update.ts +21 -0
  91. package/src/commands/web-search.ts +42 -0
  92. package/src/commit/agentic/agent.ts +311 -0
  93. package/src/commit/agentic/fallback.ts +96 -0
  94. package/src/commit/agentic/index.ts +359 -0
  95. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  96. package/src/commit/agentic/prompts/session-user.md +25 -0
  97. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  98. package/src/commit/agentic/prompts/system.md +38 -0
  99. package/src/commit/agentic/state.ts +69 -0
  100. package/src/commit/agentic/tools/analyze-file.ts +118 -0
  101. package/src/commit/agentic/tools/git-file-diff.ts +194 -0
  102. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  103. package/src/commit/agentic/tools/git-overview.ts +84 -0
  104. package/src/commit/agentic/tools/index.ts +56 -0
  105. package/src/commit/agentic/tools/propose-changelog.ts +128 -0
  106. package/src/commit/agentic/tools/propose-commit.ts +154 -0
  107. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  108. package/src/commit/agentic/tools/split-commit.ts +280 -0
  109. package/src/commit/agentic/topo-sort.ts +44 -0
  110. package/src/commit/agentic/trivial.ts +51 -0
  111. package/src/commit/agentic/validation.ts +200 -0
  112. package/src/commit/analysis/conventional.ts +165 -0
  113. package/src/commit/analysis/index.ts +4 -0
  114. package/src/commit/analysis/scope.ts +242 -0
  115. package/src/commit/analysis/summary.ts +112 -0
  116. package/src/commit/analysis/validation.ts +66 -0
  117. package/src/commit/changelog/detect.ts +37 -0
  118. package/src/commit/changelog/generate.ts +110 -0
  119. package/src/commit/changelog/index.ts +234 -0
  120. package/src/commit/changelog/parse.ts +44 -0
  121. package/src/commit/cli.ts +93 -0
  122. package/src/commit/git/diff.ts +148 -0
  123. package/src/commit/git/errors.ts +9 -0
  124. package/src/commit/git/index.ts +211 -0
  125. package/src/commit/git/operations.ts +54 -0
  126. package/src/commit/index.ts +5 -0
  127. package/src/commit/map-reduce/index.ts +64 -0
  128. package/src/commit/map-reduce/map-phase.ts +178 -0
  129. package/src/commit/map-reduce/reduce-phase.ts +145 -0
  130. package/src/commit/map-reduce/utils.ts +9 -0
  131. package/src/commit/message.ts +11 -0
  132. package/src/commit/model-selection.ts +69 -0
  133. package/src/commit/pipeline.ts +243 -0
  134. package/src/commit/prompts/analysis-system.md +148 -0
  135. package/src/commit/prompts/analysis-user.md +38 -0
  136. package/src/commit/prompts/changelog-system.md +50 -0
  137. package/src/commit/prompts/changelog-user.md +18 -0
  138. package/src/commit/prompts/file-observer-system.md +24 -0
  139. package/src/commit/prompts/file-observer-user.md +8 -0
  140. package/src/commit/prompts/reduce-system.md +50 -0
  141. package/src/commit/prompts/reduce-user.md +17 -0
  142. package/src/commit/prompts/summary-retry.md +3 -0
  143. package/src/commit/prompts/summary-system.md +38 -0
  144. package/src/commit/prompts/summary-user.md +13 -0
  145. package/src/commit/prompts/types-description.md +2 -0
  146. package/src/commit/types.ts +109 -0
  147. package/src/commit/utils/exclusions.ts +42 -0
  148. package/src/config/file-lock.ts +121 -0
  149. package/src/config/keybindings.ts +280 -0
  150. package/src/config/model-registry.ts +1140 -0
  151. package/src/config/model-resolver.ts +812 -0
  152. package/src/config/prompt-templates.ts +526 -0
  153. package/src/config/resolve-config-value.ts +92 -0
  154. package/src/config/settings-schema.ts +1236 -0
  155. package/src/config/settings.ts +706 -0
  156. package/src/config.ts +414 -0
  157. package/src/cursor.ts +239 -0
  158. package/src/debug/index.ts +431 -0
  159. package/src/debug/log-formatting.ts +60 -0
  160. package/src/debug/log-viewer.ts +903 -0
  161. package/src/debug/profiler.ts +158 -0
  162. package/src/debug/report-bundle.ts +366 -0
  163. package/src/debug/system-info.ts +112 -0
  164. package/src/discovery/agents-md.ts +68 -0
  165. package/src/discovery/agents.ts +199 -0
  166. package/src/discovery/builtin.ts +815 -0
  167. package/src/discovery/claude-plugins.ts +205 -0
  168. package/src/discovery/claude.ts +506 -0
  169. package/src/discovery/cline.ts +83 -0
  170. package/src/discovery/codex.ts +532 -0
  171. package/src/discovery/cursor.ts +218 -0
  172. package/src/discovery/gemini.ts +395 -0
  173. package/src/discovery/github.ts +117 -0
  174. package/src/discovery/helpers.ts +698 -0
  175. package/src/discovery/index.ts +89 -0
  176. package/src/discovery/mcp-json.ts +156 -0
  177. package/src/discovery/opencode.ts +394 -0
  178. package/src/discovery/ssh.ts +160 -0
  179. package/src/discovery/vscode.ts +103 -0
  180. package/src/discovery/windsurf.ts +145 -0
  181. package/src/exa/company.ts +57 -0
  182. package/src/exa/index.ts +62 -0
  183. package/src/exa/linkedin.ts +57 -0
  184. package/src/exa/mcp-client.ts +289 -0
  185. package/src/exa/render.ts +244 -0
  186. package/src/exa/researcher.ts +89 -0
  187. package/src/exa/search.ts +330 -0
  188. package/src/exa/types.ts +166 -0
  189. package/src/exa/websets.ts +247 -0
  190. package/src/exec/bash-executor.ts +184 -0
  191. package/src/exec/exec.ts +53 -0
  192. package/src/export/custom-share.ts +65 -0
  193. package/src/export/html/index.ts +162 -0
  194. package/src/export/html/template.css +889 -0
  195. package/src/export/html/template.generated.ts +2 -0
  196. package/src/export/html/template.html +45 -0
  197. package/src/export/html/template.js +1329 -0
  198. package/src/export/html/template.macro.ts +24 -0
  199. package/src/export/html/vendor/highlight.min.js +1213 -0
  200. package/src/export/html/vendor/marked.min.js +6 -0
  201. package/src/export/ttsr.ts +434 -0
  202. package/src/extensibility/custom-commands/bundled/review/index.ts +433 -0
  203. package/src/extensibility/custom-commands/index.ts +15 -0
  204. package/src/extensibility/custom-commands/loader.ts +231 -0
  205. package/src/extensibility/custom-commands/types.ts +111 -0
  206. package/src/extensibility/custom-tools/index.ts +22 -0
  207. package/src/extensibility/custom-tools/loader.ts +235 -0
  208. package/src/extensibility/custom-tools/types.ts +226 -0
  209. package/src/extensibility/custom-tools/wrapper.ts +45 -0
  210. package/src/extensibility/extensions/index.ts +136 -0
  211. package/src/extensibility/extensions/loader.ts +520 -0
  212. package/src/extensibility/extensions/runner.ts +774 -0
  213. package/src/extensibility/extensions/types.ts +1293 -0
  214. package/src/extensibility/extensions/wrapper.ts +188 -0
  215. package/src/extensibility/hooks/index.ts +16 -0
  216. package/src/extensibility/hooks/loader.ts +273 -0
  217. package/src/extensibility/hooks/runner.ts +441 -0
  218. package/src/extensibility/hooks/tool-wrapper.ts +106 -0
  219. package/src/extensibility/hooks/types.ts +817 -0
  220. package/src/extensibility/plugins/doctor.ts +65 -0
  221. package/src/extensibility/plugins/git-url.ts +281 -0
  222. package/src/extensibility/plugins/index.ts +33 -0
  223. package/src/extensibility/plugins/installer.ts +192 -0
  224. package/src/extensibility/plugins/loader.ts +338 -0
  225. package/src/extensibility/plugins/manager.ts +716 -0
  226. package/src/extensibility/plugins/parser.ts +105 -0
  227. package/src/extensibility/plugins/types.ts +190 -0
  228. package/src/extensibility/skills.ts +385 -0
  229. package/src/extensibility/slash-commands.ts +287 -0
  230. package/src/extensibility/tool-proxy.ts +25 -0
  231. package/src/index.ts +275 -0
  232. package/src/internal-urls/agent-protocol.ts +136 -0
  233. package/src/internal-urls/artifact-protocol.ts +97 -0
  234. package/src/internal-urls/docs-index.generated.ts +54 -0
  235. package/src/internal-urls/docs-protocol.ts +84 -0
  236. package/src/internal-urls/index.ts +31 -0
  237. package/src/internal-urls/json-query.ts +126 -0
  238. package/src/internal-urls/memory-protocol.ts +133 -0
  239. package/src/internal-urls/router.ts +70 -0
  240. package/src/internal-urls/rule-protocol.ts +55 -0
  241. package/src/internal-urls/skill-protocol.ts +111 -0
  242. package/src/internal-urls/types.ts +52 -0
  243. package/src/ipy/executor.ts +556 -0
  244. package/src/ipy/gateway-coordinator.ts +426 -0
  245. package/src/ipy/kernel.ts +892 -0
  246. package/src/ipy/modules.ts +109 -0
  247. package/src/ipy/prelude.py +831 -0
  248. package/src/ipy/prelude.ts +3 -0
  249. package/src/ipy/runtime.ts +222 -0
  250. package/src/lsp/client.ts +867 -0
  251. package/src/lsp/clients/biome-client.ts +202 -0
  252. package/src/lsp/clients/index.ts +50 -0
  253. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  254. package/src/lsp/clients/swiftlint-client.ts +120 -0
  255. package/src/lsp/config.ts +397 -0
  256. package/src/lsp/defaults.json +464 -0
  257. package/src/lsp/edits.ts +109 -0
  258. package/src/lsp/index.ts +1268 -0
  259. package/src/lsp/lspmux.ts +250 -0
  260. package/src/lsp/render.ts +689 -0
  261. package/src/lsp/types.ts +414 -0
  262. package/src/lsp/utils.ts +549 -0
  263. package/src/main.ts +773 -0
  264. package/src/mcp/client.ts +239 -0
  265. package/src/mcp/config-writer.ts +215 -0
  266. package/src/mcp/config.ts +363 -0
  267. package/src/mcp/index.ts +55 -0
  268. package/src/mcp/json-rpc.ts +84 -0
  269. package/src/mcp/loader.ts +124 -0
  270. package/src/mcp/manager.ts +490 -0
  271. package/src/mcp/oauth-discovery.ts +274 -0
  272. package/src/mcp/oauth-flow.ts +229 -0
  273. package/src/mcp/render.ts +123 -0
  274. package/src/mcp/tool-bridge.ts +372 -0
  275. package/src/mcp/tool-cache.ts +121 -0
  276. package/src/mcp/transports/http.ts +332 -0
  277. package/src/mcp/transports/index.ts +6 -0
  278. package/src/mcp/transports/stdio.ts +281 -0
  279. package/src/mcp/types.ts +248 -0
  280. package/src/memories/index.ts +1099 -0
  281. package/src/memories/storage.ts +563 -0
  282. package/src/modes/components/agent-dashboard.ts +1130 -0
  283. package/src/modes/components/assistant-message.ts +144 -0
  284. package/src/modes/components/bash-execution.ts +218 -0
  285. package/src/modes/components/bordered-loader.ts +41 -0
  286. package/src/modes/components/branch-summary-message.ts +45 -0
  287. package/src/modes/components/codemode-group.ts +369 -0
  288. package/src/modes/components/compaction-summary-message.ts +51 -0
  289. package/src/modes/components/countdown-timer.ts +46 -0
  290. package/src/modes/components/custom-editor.ts +181 -0
  291. package/src/modes/components/custom-message.ts +91 -0
  292. package/src/modes/components/diff.ts +186 -0
  293. package/src/modes/components/dynamic-border.ts +25 -0
  294. package/src/modes/components/extensions/extension-dashboard.ts +325 -0
  295. package/src/modes/components/extensions/extension-list.ts +484 -0
  296. package/src/modes/components/extensions/index.ts +9 -0
  297. package/src/modes/components/extensions/inspector-panel.ts +321 -0
  298. package/src/modes/components/extensions/state-manager.ts +586 -0
  299. package/src/modes/components/extensions/types.ts +191 -0
  300. package/src/modes/components/footer.ts +315 -0
  301. package/src/modes/components/history-search.ts +157 -0
  302. package/src/modes/components/hook-editor.ts +101 -0
  303. package/src/modes/components/hook-input.ts +72 -0
  304. package/src/modes/components/hook-message.ts +100 -0
  305. package/src/modes/components/hook-selector.ts +155 -0
  306. package/src/modes/components/index.ts +41 -0
  307. package/src/modes/components/keybinding-hints.ts +65 -0
  308. package/src/modes/components/login-dialog.ts +164 -0
  309. package/src/modes/components/mcp-add-wizard.ts +1295 -0
  310. package/src/modes/components/model-selector.ts +625 -0
  311. package/src/modes/components/oauth-selector.ts +210 -0
  312. package/src/modes/components/plugin-settings.ts +477 -0
  313. package/src/modes/components/python-execution.ts +196 -0
  314. package/src/modes/components/queue-mode-selector.ts +56 -0
  315. package/src/modes/components/read-tool-group.ts +119 -0
  316. package/src/modes/components/session-selector.ts +242 -0
  317. package/src/modes/components/settings-defs.ts +340 -0
  318. package/src/modes/components/settings-selector.ts +529 -0
  319. package/src/modes/components/show-images-selector.ts +45 -0
  320. package/src/modes/components/skill-message.ts +90 -0
  321. package/src/modes/components/status-line/index.ts +4 -0
  322. package/src/modes/components/status-line/presets.ts +94 -0
  323. package/src/modes/components/status-line/segments.ts +352 -0
  324. package/src/modes/components/status-line/separators.ts +55 -0
  325. package/src/modes/components/status-line/types.ts +75 -0
  326. package/src/modes/components/status-line-segment-editor.ts +354 -0
  327. package/src/modes/components/status-line.ts +421 -0
  328. package/src/modes/components/theme-selector.ts +63 -0
  329. package/src/modes/components/thinking-selector.ts +64 -0
  330. package/src/modes/components/todo-display.ts +115 -0
  331. package/src/modes/components/todo-reminder.ts +40 -0
  332. package/src/modes/components/tool-execution.ts +703 -0
  333. package/src/modes/components/tree-selector.ts +904 -0
  334. package/src/modes/components/ttsr-notification.ts +80 -0
  335. package/src/modes/components/user-message-selector.ts +146 -0
  336. package/src/modes/components/user-message.ts +22 -0
  337. package/src/modes/components/visual-truncate.ts +63 -0
  338. package/src/modes/components/welcome.ts +247 -0
  339. package/src/modes/controllers/command-controller.ts +1120 -0
  340. package/src/modes/controllers/event-controller.ts +479 -0
  341. package/src/modes/controllers/extension-ui-controller.ts +778 -0
  342. package/src/modes/controllers/input-controller.ts +671 -0
  343. package/src/modes/controllers/mcp-command-controller.ts +1315 -0
  344. package/src/modes/controllers/selector-controller.ts +712 -0
  345. package/src/modes/controllers/ssh-command-controller.ts +452 -0
  346. package/src/modes/index.ts +15 -0
  347. package/src/modes/interactive-mode.ts +1027 -0
  348. package/src/modes/print-mode.ts +191 -0
  349. package/src/modes/rpc/rpc-client.ts +583 -0
  350. package/src/modes/rpc/rpc-mode.ts +700 -0
  351. package/src/modes/rpc/rpc-types.ts +236 -0
  352. package/src/modes/theme/dark.json +95 -0
  353. package/src/modes/theme/defaults/alabaster.json +93 -0
  354. package/src/modes/theme/defaults/amethyst.json +96 -0
  355. package/src/modes/theme/defaults/anthracite.json +93 -0
  356. package/src/modes/theme/defaults/basalt.json +91 -0
  357. package/src/modes/theme/defaults/birch.json +95 -0
  358. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  359. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  360. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  361. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  362. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  363. package/src/modes/theme/defaults/dark-copper.json +95 -0
  364. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  365. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  366. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  367. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  368. package/src/modes/theme/defaults/dark-ember.json +95 -0
  369. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  370. package/src/modes/theme/defaults/dark-forest.json +96 -0
  371. package/src/modes/theme/defaults/dark-github.json +105 -0
  372. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  373. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  374. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  375. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  376. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  377. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  378. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  379. package/src/modes/theme/defaults/dark-nord.json +97 -0
  380. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  381. package/src/modes/theme/defaults/dark-one.json +100 -0
  382. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  383. package/src/modes/theme/defaults/dark-reef.json +91 -0
  384. package/src/modes/theme/defaults/dark-retro.json +92 -0
  385. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  386. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  387. package/src/modes/theme/defaults/dark-slate.json +95 -0
  388. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  389. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  390. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  391. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  392. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  393. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  394. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  395. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  396. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  397. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  398. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  399. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  400. package/src/modes/theme/defaults/graphite.json +92 -0
  401. package/src/modes/theme/defaults/index.ts +195 -0
  402. package/src/modes/theme/defaults/light-arctic.json +107 -0
  403. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  404. package/src/modes/theme/defaults/light-canyon.json +91 -0
  405. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  406. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  407. package/src/modes/theme/defaults/light-coral.json +95 -0
  408. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  409. package/src/modes/theme/defaults/light-dawn.json +90 -0
  410. package/src/modes/theme/defaults/light-dunes.json +91 -0
  411. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  412. package/src/modes/theme/defaults/light-forest.json +100 -0
  413. package/src/modes/theme/defaults/light-frost.json +95 -0
  414. package/src/modes/theme/defaults/light-github.json +115 -0
  415. package/src/modes/theme/defaults/light-glacier.json +91 -0
  416. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  417. package/src/modes/theme/defaults/light-haze.json +90 -0
  418. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  419. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  420. package/src/modes/theme/defaults/light-lavender.json +95 -0
  421. package/src/modes/theme/defaults/light-meadow.json +91 -0
  422. package/src/modes/theme/defaults/light-mint.json +95 -0
  423. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  424. package/src/modes/theme/defaults/light-ocean.json +99 -0
  425. package/src/modes/theme/defaults/light-one.json +99 -0
  426. package/src/modes/theme/defaults/light-opal.json +91 -0
  427. package/src/modes/theme/defaults/light-orchard.json +91 -0
  428. package/src/modes/theme/defaults/light-paper.json +95 -0
  429. package/src/modes/theme/defaults/light-prism.json +90 -0
  430. package/src/modes/theme/defaults/light-retro.json +98 -0
  431. package/src/modes/theme/defaults/light-sand.json +95 -0
  432. package/src/modes/theme/defaults/light-savanna.json +91 -0
  433. package/src/modes/theme/defaults/light-solarized.json +102 -0
  434. package/src/modes/theme/defaults/light-soleil.json +90 -0
  435. package/src/modes/theme/defaults/light-sunset.json +99 -0
  436. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  437. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  438. package/src/modes/theme/defaults/light-wetland.json +91 -0
  439. package/src/modes/theme/defaults/light-zenith.json +89 -0
  440. package/src/modes/theme/defaults/limestone.json +94 -0
  441. package/src/modes/theme/defaults/mahogany.json +97 -0
  442. package/src/modes/theme/defaults/marble.json +93 -0
  443. package/src/modes/theme/defaults/obsidian.json +91 -0
  444. package/src/modes/theme/defaults/onyx.json +91 -0
  445. package/src/modes/theme/defaults/pearl.json +93 -0
  446. package/src/modes/theme/defaults/porcelain.json +91 -0
  447. package/src/modes/theme/defaults/quartz.json +96 -0
  448. package/src/modes/theme/defaults/sandstone.json +95 -0
  449. package/src/modes/theme/defaults/titanium.json +90 -0
  450. package/src/modes/theme/light.json +93 -0
  451. package/src/modes/theme/mermaid-cache.ts +111 -0
  452. package/src/modes/theme/theme-schema.json +429 -0
  453. package/src/modes/theme/theme.ts +2333 -0
  454. package/src/modes/types.ts +216 -0
  455. package/src/modes/utils/ui-helpers.ts +529 -0
  456. package/src/patch/applicator.ts +1482 -0
  457. package/src/patch/diff.ts +425 -0
  458. package/src/patch/fuzzy.ts +784 -0
  459. package/src/patch/hashline.ts +972 -0
  460. package/src/patch/index.ts +964 -0
  461. package/src/patch/normalize.ts +397 -0
  462. package/src/patch/normative.ts +72 -0
  463. package/src/patch/parser.ts +532 -0
  464. package/src/patch/shared.ts +400 -0
  465. package/src/patch/types.ts +292 -0
  466. package/src/priority.json +35 -0
  467. package/src/prompts/agents/explore.md +48 -0
  468. package/src/prompts/agents/frontmatter.md +9 -0
  469. package/src/prompts/agents/init.md +36 -0
  470. package/src/prompts/agents/librarian.md +53 -0
  471. package/src/prompts/agents/oracle.md +51 -0
  472. package/src/prompts/agents/reviewer.md +70 -0
  473. package/src/prompts/agents/task.md +14 -0
  474. package/src/prompts/compaction/branch-summary-context.md +5 -0
  475. package/src/prompts/compaction/branch-summary-preamble.md +2 -0
  476. package/src/prompts/compaction/branch-summary.md +30 -0
  477. package/src/prompts/compaction/compaction-short-summary.md +9 -0
  478. package/src/prompts/compaction/compaction-summary-context.md +5 -0
  479. package/src/prompts/compaction/compaction-summary.md +38 -0
  480. package/src/prompts/compaction/compaction-turn-prefix.md +17 -0
  481. package/src/prompts/compaction/compaction-update-summary.md +45 -0
  482. package/src/prompts/memories/consolidation.md +30 -0
  483. package/src/prompts/memories/read_path.md +11 -0
  484. package/src/prompts/memories/stage_one_input.md +6 -0
  485. package/src/prompts/memories/stage_one_system.md +21 -0
  486. package/src/prompts/review-request.md +64 -0
  487. package/src/prompts/system/agent-creation-architect.md +65 -0
  488. package/src/prompts/system/agent-creation-user.md +6 -0
  489. package/src/prompts/system/custom-system-prompt.md +68 -0
  490. package/src/prompts/system/file-operations.md +10 -0
  491. package/src/prompts/system/subagent-submit-reminder.md +11 -0
  492. package/src/prompts/system/subagent-system-prompt.md +31 -0
  493. package/src/prompts/system/subagent-user-prompt.md +8 -0
  494. package/src/prompts/system/summarization-system.md +3 -0
  495. package/src/prompts/system/system-prompt.md +300 -0
  496. package/src/prompts/system/title-system.md +2 -0
  497. package/src/prompts/system/ttsr-interrupt.md +7 -0
  498. package/src/prompts/system/web-search.md +28 -0
  499. package/src/prompts/tools/ask.md +44 -0
  500. package/src/prompts/tools/bash.md +24 -0
  501. package/src/prompts/tools/browser.md +33 -0
  502. package/src/prompts/tools/calculator.md +12 -0
  503. package/src/prompts/tools/explore.md +29 -0
  504. package/src/prompts/tools/fetch.md +16 -0
  505. package/src/prompts/tools/find.md +18 -0
  506. package/src/prompts/tools/gemini-image.md +23 -0
  507. package/src/prompts/tools/grep.md +28 -0
  508. package/src/prompts/tools/hashline.md +232 -0
  509. package/src/prompts/tools/librarian.md +24 -0
  510. package/src/prompts/tools/lsp.md +28 -0
  511. package/src/prompts/tools/oracle.md +26 -0
  512. package/src/prompts/tools/patch.md +74 -0
  513. package/src/prompts/tools/python.md +66 -0
  514. package/src/prompts/tools/read.md +36 -0
  515. package/src/prompts/tools/replace.md +38 -0
  516. package/src/prompts/tools/reviewer.md +41 -0
  517. package/src/prompts/tools/ssh.md +51 -0
  518. package/src/prompts/tools/task-summary.md +28 -0
  519. package/src/prompts/tools/task.md +275 -0
  520. package/src/prompts/tools/todo-write.md +65 -0
  521. package/src/prompts/tools/undo-edit.md +7 -0
  522. package/src/prompts/tools/web-search.md +19 -0
  523. package/src/prompts/tools/write.md +18 -0
  524. package/src/sdk.ts +1287 -0
  525. package/src/secrets/index.ts +116 -0
  526. package/src/secrets/obfuscator.ts +269 -0
  527. package/src/secrets/regex.ts +21 -0
  528. package/src/session/agent-session.ts +4669 -0
  529. package/src/session/agent-storage.ts +621 -0
  530. package/src/session/artifacts.ts +132 -0
  531. package/src/session/auth-storage.ts +1433 -0
  532. package/src/session/blob-store.ts +103 -0
  533. package/src/session/compaction/branch-summarization.ts +315 -0
  534. package/src/session/compaction/compaction.ts +864 -0
  535. package/src/session/compaction/index.ts +7 -0
  536. package/src/session/compaction/pruning.ts +91 -0
  537. package/src/session/compaction/utils.ts +171 -0
  538. package/src/session/history-storage.ts +170 -0
  539. package/src/session/messages.ts +317 -0
  540. package/src/session/session-manager.ts +2276 -0
  541. package/src/session/session-storage.ts +342 -0
  542. package/src/session/streaming-output.ts +565 -0
  543. package/src/slash-commands/builtin-registry.ts +439 -0
  544. package/src/ssh/config-writer.ts +183 -0
  545. package/src/ssh/connection-manager.ts +444 -0
  546. package/src/ssh/ssh-executor.ts +127 -0
  547. package/src/ssh/sshfs-mount.ts +135 -0
  548. package/src/stt/downloader.ts +71 -0
  549. package/src/stt/index.ts +3 -0
  550. package/src/stt/recorder.ts +351 -0
  551. package/src/stt/setup.ts +52 -0
  552. package/src/stt/stt-controller.ts +160 -0
  553. package/src/stt/transcribe.py +70 -0
  554. package/src/stt/transcriber.ts +91 -0
  555. package/src/system-prompt.ts +685 -0
  556. package/src/task/agents.ts +155 -0
  557. package/src/task/batch.ts +102 -0
  558. package/src/task/commands.ts +134 -0
  559. package/src/task/discovery.ts +126 -0
  560. package/src/task/executor.ts +908 -0
  561. package/src/task/index.ts +223 -0
  562. package/src/task/output-manager.ts +107 -0
  563. package/src/task/parallel.ts +84 -0
  564. package/src/task/render.ts +326 -0
  565. package/src/task/subprocess-tool-registry.ts +88 -0
  566. package/src/task/template.ts +32 -0
  567. package/src/task/types.ts +144 -0
  568. package/src/tools/ask.ts +523 -0
  569. package/src/tools/bash-interactive.ts +419 -0
  570. package/src/tools/bash-interceptor.ts +105 -0
  571. package/src/tools/bash-normalize.ts +107 -0
  572. package/src/tools/bash-skill-urls.ts +177 -0
  573. package/src/tools/bash.ts +347 -0
  574. package/src/tools/browser.ts +1374 -0
  575. package/src/tools/calculator.ts +537 -0
  576. package/src/tools/context.ts +39 -0
  577. package/src/tools/explore.ts +23 -0
  578. package/src/tools/fetch.ts +1091 -0
  579. package/src/tools/find.ts +540 -0
  580. package/src/tools/fs-cache-invalidation.ts +28 -0
  581. package/src/tools/gemini-image.ts +907 -0
  582. package/src/tools/grep.ts +489 -0
  583. package/src/tools/index.ts +337 -0
  584. package/src/tools/json-tree.ts +231 -0
  585. package/src/tools/jtd-to-json-schema.ts +247 -0
  586. package/src/tools/jtd-to-typescript.ts +198 -0
  587. package/src/tools/librarian.ts +33 -0
  588. package/src/tools/list-limit.ts +40 -0
  589. package/src/tools/notebook.ts +287 -0
  590. package/src/tools/oracle.ts +40 -0
  591. package/src/tools/output-meta.ts +459 -0
  592. package/src/tools/output-utils.ts +63 -0
  593. package/src/tools/path-utils.ts +116 -0
  594. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  595. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  596. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  597. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  598. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  599. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  600. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  601. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  602. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  603. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  604. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  605. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  606. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  607. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  608. package/src/tools/python.ts +1118 -0
  609. package/src/tools/read.ts +1193 -0
  610. package/src/tools/render-utils.ts +680 -0
  611. package/src/tools/renderers.ts +60 -0
  612. package/src/tools/reviewer-tool.ts +41 -0
  613. package/src/tools/ssh.ts +326 -0
  614. package/src/tools/subagent-tool.ts +169 -0
  615. package/src/tools/submit-result.ts +152 -0
  616. package/src/tools/todo-write.ts +255 -0
  617. package/src/tools/tool-errors.ts +92 -0
  618. package/src/tools/tool-result.ts +86 -0
  619. package/src/tools/undo-edit.ts +145 -0
  620. package/src/tools/undo-history.ts +22 -0
  621. package/src/tools/write.ts +274 -0
  622. package/src/tui/code-cell.ts +108 -0
  623. package/src/tui/file-list.ts +47 -0
  624. package/src/tui/index.ts +11 -0
  625. package/src/tui/output-block.ts +144 -0
  626. package/src/tui/status-line.ts +39 -0
  627. package/src/tui/tree-list.ts +53 -0
  628. package/src/tui/types.ts +16 -0
  629. package/src/tui/utils.ts +116 -0
  630. package/src/utils/changelog.ts +98 -0
  631. package/src/utils/event-bus.ts +33 -0
  632. package/src/utils/external-editor.ts +59 -0
  633. package/src/utils/file-display-mode.ts +36 -0
  634. package/src/utils/file-mentions.ts +384 -0
  635. package/src/utils/frontmatter.ts +101 -0
  636. package/src/utils/fuzzy.ts +108 -0
  637. package/src/utils/ignore-files.ts +119 -0
  638. package/src/utils/image-convert.ts +27 -0
  639. package/src/utils/image-resize.ts +236 -0
  640. package/src/utils/mime.ts +30 -0
  641. package/src/utils/open.ts +20 -0
  642. package/src/utils/shell-snapshot.ts +199 -0
  643. package/src/utils/timings.ts +26 -0
  644. package/src/utils/title-generator.ts +167 -0
  645. package/src/utils/tools-manager.ts +362 -0
  646. package/src/web/scrapers/artifacthub.ts +215 -0
  647. package/src/web/scrapers/arxiv.ts +88 -0
  648. package/src/web/scrapers/aur.ts +175 -0
  649. package/src/web/scrapers/biorxiv.ts +141 -0
  650. package/src/web/scrapers/bluesky.ts +284 -0
  651. package/src/web/scrapers/brew.ts +177 -0
  652. package/src/web/scrapers/cheatsh.ts +78 -0
  653. package/src/web/scrapers/chocolatey.ts +158 -0
  654. package/src/web/scrapers/choosealicense.ts +110 -0
  655. package/src/web/scrapers/cisa-kev.ts +100 -0
  656. package/src/web/scrapers/clojars.ts +180 -0
  657. package/src/web/scrapers/coingecko.ts +184 -0
  658. package/src/web/scrapers/crates-io.ts +128 -0
  659. package/src/web/scrapers/crossref.ts +149 -0
  660. package/src/web/scrapers/devto.ts +177 -0
  661. package/src/web/scrapers/discogs.ts +307 -0
  662. package/src/web/scrapers/discourse.ts +221 -0
  663. package/src/web/scrapers/dockerhub.ts +160 -0
  664. package/src/web/scrapers/fdroid.ts +158 -0
  665. package/src/web/scrapers/firefox-addons.ts +214 -0
  666. package/src/web/scrapers/flathub.ts +239 -0
  667. package/src/web/scrapers/github-gist.ts +68 -0
  668. package/src/web/scrapers/github.ts +490 -0
  669. package/src/web/scrapers/gitlab.ts +456 -0
  670. package/src/web/scrapers/go-pkg.ts +275 -0
  671. package/src/web/scrapers/hackage.ts +94 -0
  672. package/src/web/scrapers/hackernews.ts +208 -0
  673. package/src/web/scrapers/hex.ts +121 -0
  674. package/src/web/scrapers/huggingface.ts +385 -0
  675. package/src/web/scrapers/iacr.ts +86 -0
  676. package/src/web/scrapers/index.ts +249 -0
  677. package/src/web/scrapers/jetbrains-marketplace.ts +169 -0
  678. package/src/web/scrapers/lemmy.ts +220 -0
  679. package/src/web/scrapers/lobsters.ts +186 -0
  680. package/src/web/scrapers/mastodon.ts +310 -0
  681. package/src/web/scrapers/maven.ts +152 -0
  682. package/src/web/scrapers/mdn.ts +172 -0
  683. package/src/web/scrapers/metacpan.ts +253 -0
  684. package/src/web/scrapers/musicbrainz.ts +272 -0
  685. package/src/web/scrapers/npm.ts +114 -0
  686. package/src/web/scrapers/nuget.ts +205 -0
  687. package/src/web/scrapers/nvd.ts +243 -0
  688. package/src/web/scrapers/ollama.ts +265 -0
  689. package/src/web/scrapers/open-vsx.ts +119 -0
  690. package/src/web/scrapers/opencorporates.ts +275 -0
  691. package/src/web/scrapers/openlibrary.ts +319 -0
  692. package/src/web/scrapers/orcid.ts +298 -0
  693. package/src/web/scrapers/osv.ts +192 -0
  694. package/src/web/scrapers/packagist.ts +174 -0
  695. package/src/web/scrapers/pub-dev.ts +185 -0
  696. package/src/web/scrapers/pubmed.ts +177 -0
  697. package/src/web/scrapers/pypi.ts +129 -0
  698. package/src/web/scrapers/rawg.ts +124 -0
  699. package/src/web/scrapers/readthedocs.ts +125 -0
  700. package/src/web/scrapers/reddit.ts +104 -0
  701. package/src/web/scrapers/repology.ts +262 -0
  702. package/src/web/scrapers/rfc.ts +209 -0
  703. package/src/web/scrapers/rubygems.ts +117 -0
  704. package/src/web/scrapers/searchcode.ts +217 -0
  705. package/src/web/scrapers/sec-edgar.ts +274 -0
  706. package/src/web/scrapers/semantic-scholar.ts +190 -0
  707. package/src/web/scrapers/snapcraft.ts +200 -0
  708. package/src/web/scrapers/sourcegraph.ts +373 -0
  709. package/src/web/scrapers/spdx.ts +121 -0
  710. package/src/web/scrapers/spotify.ts +217 -0
  711. package/src/web/scrapers/stackoverflow.ts +124 -0
  712. package/src/web/scrapers/terraform.ts +304 -0
  713. package/src/web/scrapers/tldr.ts +51 -0
  714. package/src/web/scrapers/twitter.ts +97 -0
  715. package/src/web/scrapers/types.ts +200 -0
  716. package/src/web/scrapers/utils.ts +142 -0
  717. package/src/web/scrapers/vimeo.ts +152 -0
  718. package/src/web/scrapers/vscode-marketplace.ts +195 -0
  719. package/src/web/scrapers/w3c.ts +163 -0
  720. package/src/web/scrapers/wikidata.ts +357 -0
  721. package/src/web/scrapers/wikipedia.ts +95 -0
  722. package/src/web/scrapers/youtube.ts +312 -0
  723. package/src/web/search/auth.ts +178 -0
  724. package/src/web/search/index.ts +598 -0
  725. package/src/web/search/provider.ts +77 -0
  726. package/src/web/search/providers/anthropic.ts +284 -0
  727. package/src/web/search/providers/base.ts +22 -0
  728. package/src/web/search/providers/brave.ts +165 -0
  729. package/src/web/search/providers/codex.ts +377 -0
  730. package/src/web/search/providers/exa.ts +158 -0
  731. package/src/web/search/providers/gemini.ts +437 -0
  732. package/src/web/search/providers/jina.ts +99 -0
  733. package/src/web/search/providers/kimi.ts +196 -0
  734. package/src/web/search/providers/perplexity.ts +546 -0
  735. package/src/web/search/providers/synthetic.ts +136 -0
  736. package/src/web/search/providers/zai.ts +352 -0
  737. package/src/web/search/render.ts +299 -0
  738. package/src/web/search/types.ts +437 -0
@@ -0,0 +1,621 @@
1
+ import { Database, type Statement } from "bun:sqlite";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { logger } from "@nghyane/arcane-utils";
5
+ import { getAgentDbPath } from "@nghyane/arcane-utils/dirs";
6
+ import type { RawSettings as Settings } from "../config/settings";
7
+ import type { AuthCredential } from "./auth-storage";
8
+
9
+ /** Row shape for settings table queries */
10
+ type SettingsRow = {
11
+ key: string;
12
+ value: string;
13
+ };
14
+
15
+ /** Row shape for auth_credentials table queries */
16
+ type AuthRow = {
17
+ id: number;
18
+ provider: string;
19
+ credential_type: string;
20
+ data: string;
21
+ };
22
+
23
+ /** Row shape for model_usage table queries */
24
+ type ModelUsageRow = {
25
+ model_key: string;
26
+ last_used_at: number;
27
+ };
28
+
29
+ /**
30
+ * Auth credential with database row ID for updates/deletes.
31
+ * Wraps AuthCredential with storage metadata.
32
+ */
33
+ export interface StoredAuthCredential {
34
+ id: number;
35
+ provider: string;
36
+ credential: AuthCredential;
37
+ }
38
+
39
+ /** Bump when schema changes require migration */
40
+ const SCHEMA_VERSION = 4;
41
+
42
+ /**
43
+ * Type guard for plain objects.
44
+ * @param value - Value to check
45
+ * @returns True if value is a non-null, non-array object
46
+ */
47
+ function isRecord(value: unknown): value is Record<string, unknown> {
48
+ return !!value && typeof value === "object" && !Array.isArray(value);
49
+ }
50
+
51
+ /**
52
+ * Converts credential to DB format, stripping the type discriminant from the data blob.
53
+ * @param credential - The credential to serialize
54
+ * @returns Object with credentialType and JSON data string, or null for unknown types
55
+ */
56
+ function serializeCredential(
57
+ credential: AuthCredential,
58
+ ): { credentialType: AuthCredential["type"]; data: string } | null {
59
+ if (credential.type === "api_key") {
60
+ return {
61
+ credentialType: "api_key",
62
+ data: JSON.stringify({ key: credential.key }),
63
+ };
64
+ }
65
+ if (credential.type === "oauth") {
66
+ const { type: _type, ...rest } = credential;
67
+ return {
68
+ credentialType: "oauth",
69
+ data: JSON.stringify(rest),
70
+ };
71
+ }
72
+ return null;
73
+ }
74
+
75
+ /**
76
+ * Reconstructs credential from DB row, re-adding the type discriminant.
77
+ * @param row - Database row containing credential data
78
+ * @returns Reconstructed AuthCredential, or null if parsing fails or type is unknown
79
+ */
80
+ function deserializeCredential(row: AuthRow): AuthCredential | null {
81
+ let parsed: unknown;
82
+ try {
83
+ parsed = JSON.parse(row.data);
84
+ } catch (error) {
85
+ logger.warn("AgentStorage failed to parse auth credential", {
86
+ provider: row.provider,
87
+ id: row.id,
88
+ error: String(error),
89
+ });
90
+ return null;
91
+ }
92
+ if (!isRecord(parsed)) {
93
+ logger.warn("AgentStorage auth credential data invalid", {
94
+ provider: row.provider,
95
+ id: row.id,
96
+ });
97
+ return null;
98
+ }
99
+ if (row.credential_type === "api_key") {
100
+ return { type: "api_key", ...(parsed as Record<string, unknown>) } as AuthCredential;
101
+ }
102
+ if (row.credential_type === "oauth") {
103
+ return { type: "oauth", ...(parsed as Record<string, unknown>) } as AuthCredential;
104
+ }
105
+ logger.warn("AgentStorage unknown credential type", {
106
+ provider: row.provider,
107
+ id: row.id,
108
+ type: row.credential_type,
109
+ });
110
+ return null;
111
+ }
112
+
113
+ /**
114
+ * Unified SQLite storage for agent settings and auth credentials.
115
+ * Uses singleton pattern per database path; access via AgentStorage.open().
116
+ */
117
+ export class AgentStorage {
118
+ #db: Database;
119
+ static #instances = new Map<string, AgentStorage>();
120
+
121
+ #listSettingsStmt: Statement;
122
+ #getCacheStmt: Statement;
123
+ #upsertCacheStmt: Statement;
124
+ #deleteExpiredCacheStmt: Statement;
125
+ #listAuthStmt: Statement;
126
+ #listAuthByProviderStmt: Statement;
127
+ #listActiveAuthStmt: Statement;
128
+ #listActiveAuthByProviderStmt: Statement;
129
+ #insertAuthStmt: Statement;
130
+ #updateAuthStmt: Statement;
131
+ #deleteAuthStmt: Statement;
132
+ #deleteAuthByProviderStmt: Statement;
133
+ #countAuthStmt: Statement;
134
+ #disableAuthStmt: Statement;
135
+ #upsertModelUsageStmt: Statement;
136
+ #listModelUsageStmt: Statement;
137
+ #modelUsageCache: string[] | null = null;
138
+
139
+ private constructor(dbPath: string) {
140
+ this.#ensureDir(dbPath);
141
+ try {
142
+ this.#db = new Database(dbPath);
143
+ } catch (err) {
144
+ const dir = path.dirname(dbPath);
145
+ const dirExists = fs.existsSync(dir);
146
+ const errMsg = err instanceof Error ? err.message : String(err);
147
+ throw new Error(
148
+ `Failed to open agent database at '${dbPath}': ${errMsg}\n` +
149
+ `Directory '${dir}' exists: ${dirExists}\n` +
150
+ `Ensure the directory is writable and not corrupted.`,
151
+ );
152
+ }
153
+
154
+ this.#initializeSchema();
155
+ this.#hardenPermissions(dbPath);
156
+
157
+ this.#listSettingsStmt = this.#db.prepare("SELECT key, value FROM settings");
158
+
159
+ this.#getCacheStmt = this.#db.prepare("SELECT value FROM cache WHERE key = ? AND expires_at > unixepoch()");
160
+ this.#upsertCacheStmt = this.#db.prepare(
161
+ "INSERT INTO cache (key, value, expires_at) VALUES (?, ?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at",
162
+ );
163
+ this.#deleteExpiredCacheStmt = this.#db.prepare("DELETE FROM cache WHERE expires_at <= unixepoch()");
164
+
165
+ this.#listAuthStmt = this.#db.prepare(
166
+ "SELECT id, provider, credential_type, data FROM auth_credentials ORDER BY id ASC",
167
+ );
168
+ this.#listAuthByProviderStmt = this.#db.prepare(
169
+ "SELECT id, provider, credential_type, data FROM auth_credentials WHERE provider = ? ORDER BY id ASC",
170
+ );
171
+ this.#listActiveAuthStmt = this.#db.prepare(
172
+ "SELECT id, provider, credential_type, data FROM auth_credentials WHERE disabled = 0 ORDER BY id ASC",
173
+ );
174
+ this.#listActiveAuthByProviderStmt = this.#db.prepare(
175
+ "SELECT id, provider, credential_type, data FROM auth_credentials WHERE provider = ? AND disabled = 0 ORDER BY id ASC",
176
+ );
177
+ this.#insertAuthStmt = this.#db.prepare(
178
+ "INSERT INTO auth_credentials (provider, credential_type, data) VALUES (?, ?, ?) RETURNING id",
179
+ );
180
+ this.#updateAuthStmt = this.#db.prepare(
181
+ "UPDATE auth_credentials SET credential_type = ?, data = ?, updated_at = unixepoch() WHERE id = ?",
182
+ );
183
+ this.#deleteAuthStmt = this.#db.prepare("DELETE FROM auth_credentials WHERE id = ?");
184
+ this.#deleteAuthByProviderStmt = this.#db.prepare("DELETE FROM auth_credentials WHERE provider = ?");
185
+ this.#disableAuthStmt = this.#db.prepare(
186
+ "UPDATE auth_credentials SET disabled = 1, updated_at = unixepoch() WHERE id = ?",
187
+ );
188
+ this.#countAuthStmt = this.#db.prepare("SELECT COUNT(*) as count FROM auth_credentials");
189
+
190
+ this.#upsertModelUsageStmt = this.#db.prepare(
191
+ "INSERT INTO model_usage (model_key, last_used_at) VALUES (?, unixepoch()) ON CONFLICT(model_key) DO UPDATE SET last_used_at = unixepoch()",
192
+ );
193
+ this.#listModelUsageStmt = this.#db.prepare(
194
+ "SELECT model_key, last_used_at FROM model_usage ORDER BY last_used_at DESC",
195
+ );
196
+ }
197
+
198
+ /**
199
+ * Creates tables if missing and migrates legacy single-blob settings to key-value format.
200
+ * Handles v1 to v2 schema migration for settings table.
201
+ */
202
+ #initializeSchema(): void {
203
+ this.#db.exec(`
204
+ PRAGMA journal_mode=WAL;
205
+ PRAGMA synchronous=NORMAL;
206
+ PRAGMA busy_timeout=5000;
207
+
208
+ CREATE TABLE IF NOT EXISTS auth_credentials (
209
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
210
+ provider TEXT NOT NULL,
211
+ credential_type TEXT NOT NULL,
212
+ data TEXT NOT NULL,
213
+ disabled INTEGER NOT NULL DEFAULT 0,
214
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
215
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
216
+ );
217
+ CREATE INDEX IF NOT EXISTS idx_auth_provider ON auth_credentials(provider);
218
+
219
+ CREATE TABLE IF NOT EXISTS cache (
220
+ key TEXT PRIMARY KEY,
221
+ value TEXT NOT NULL,
222
+ expires_at INTEGER NOT NULL
223
+ );
224
+ CREATE INDEX IF NOT EXISTS idx_cache_expires ON cache(expires_at);
225
+
226
+ CREATE TABLE IF NOT EXISTS model_usage (
227
+ model_key TEXT PRIMARY KEY,
228
+ last_used_at INTEGER NOT NULL DEFAULT (unixepoch())
229
+ );
230
+
231
+ CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY);
232
+ `);
233
+
234
+ const settingsInfo = this.#db.prepare("PRAGMA table_info(settings)").all() as Array<{ name?: string }>;
235
+ const hasSettingsTable = settingsInfo.length > 0;
236
+ const hasKey = settingsInfo.some(column => column.name === "key");
237
+ const hasValue = settingsInfo.some(column => column.name === "value");
238
+
239
+ if (!hasSettingsTable) {
240
+ this.#db.exec(`
241
+ CREATE TABLE settings (
242
+ key TEXT PRIMARY KEY,
243
+ value TEXT NOT NULL,
244
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
245
+ );
246
+ `);
247
+ } else if (!hasKey || !hasValue) {
248
+ // Migrate v1 schema: single JSON blob in `data` column → per-key rows
249
+ let legacySettings: Record<string, unknown> | null = null;
250
+ const row = this.#db.prepare("SELECT data FROM settings WHERE id = 1").get() as { data?: string } | undefined;
251
+ if (row?.data) {
252
+ try {
253
+ const parsed = JSON.parse(row.data);
254
+ if (isRecord(parsed)) {
255
+ legacySettings = parsed;
256
+ } else {
257
+ logger.warn("AgentStorage legacy settings invalid shape");
258
+ }
259
+ } catch (error) {
260
+ logger.warn("AgentStorage failed to parse legacy settings", { error: String(error) });
261
+ }
262
+ }
263
+
264
+ const migrate = this.#db.transaction((settings: Record<string, unknown> | null) => {
265
+ this.#db.exec("DROP TABLE settings");
266
+ this.#db.exec(`
267
+ CREATE TABLE settings (
268
+ key TEXT PRIMARY KEY,
269
+ value TEXT NOT NULL,
270
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch())
271
+ );
272
+ `);
273
+ if (settings) {
274
+ const insert = this.#db.prepare(
275
+ "INSERT INTO settings (key, value, updated_at) VALUES (?, ?, unixepoch())",
276
+ );
277
+ for (const [key, value] of Object.entries(settings)) {
278
+ if (value === undefined) continue;
279
+ const serialized = JSON.stringify(value);
280
+ if (serialized === undefined) continue;
281
+ insert.run(key, serialized);
282
+ }
283
+ }
284
+ });
285
+
286
+ migrate(legacySettings);
287
+ }
288
+
289
+ const versionRow = this.#db.prepare("SELECT version FROM schema_version ORDER BY version DESC LIMIT 1").get() as
290
+ | { version?: number }
291
+ | undefined;
292
+ if (versionRow?.version !== undefined && versionRow.version !== SCHEMA_VERSION) {
293
+ logger.warn("AgentStorage schema version mismatch", {
294
+ current: versionRow.version,
295
+ expected: SCHEMA_VERSION,
296
+ });
297
+ this.#migrateSchema(versionRow.version);
298
+ }
299
+ this.#db.prepare("INSERT OR REPLACE INTO schema_version(version) VALUES (?)").run(SCHEMA_VERSION);
300
+ }
301
+
302
+ #migrateSchema(fromVersion: number): void {
303
+ if (fromVersion < 4) {
304
+ // v3 → v4: Add disabled column to auth_credentials
305
+ const cols = this.#db.prepare("PRAGMA table_info(auth_credentials)").all() as Array<{ name?: string }>;
306
+ if (!cols.some(c => c.name === "disabled")) {
307
+ this.#db.exec("ALTER TABLE auth_credentials ADD COLUMN disabled INTEGER NOT NULL DEFAULT 0");
308
+ }
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Returns singleton instance for the given database path, creating if needed.
314
+ * Retries on SQLITE_BUSY with exponential backoff.
315
+ * @param dbPath - Path to the SQLite database file (defaults to config path)
316
+ * @returns AgentStorage instance for the given path
317
+ */
318
+ static async open(dbPath: string = getAgentDbPath()): Promise<AgentStorage> {
319
+ const existing = AgentStorage.#instances.get(dbPath);
320
+ if (existing) return existing;
321
+
322
+ const maxRetries = 3;
323
+ const baseDelayMs = 100;
324
+ let lastError: Error | undefined;
325
+
326
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
327
+ try {
328
+ const storage = new AgentStorage(dbPath);
329
+ AgentStorage.#instances.set(dbPath, storage);
330
+ return storage;
331
+ } catch (err) {
332
+ const isSqliteBusy = err && typeof err === "object" && (err as { code?: string }).code === "SQLITE_BUSY";
333
+ if (!isSqliteBusy) {
334
+ throw err;
335
+ }
336
+ lastError = err as Error;
337
+ const delayMs = baseDelayMs * 2 ** attempt;
338
+ await Bun.sleep(delayMs);
339
+ }
340
+ }
341
+
342
+ throw lastError ?? new Error("Failed to open database after retries");
343
+ }
344
+
345
+ /**
346
+ * Retrieves all settings from storage (legacy, for migration only).
347
+ * Settings are now stored in config.yml. This method is only used
348
+ * during migration from agent.db to config.yml.
349
+ * @returns Settings object, or null if no settings are stored
350
+ * @deprecated Use config.yml instead. This is only for migration.
351
+ */
352
+ getSettings(): Settings | null {
353
+ const rows = (this.#listSettingsStmt.all() as SettingsRow[]) ?? [];
354
+ if (rows.length === 0) return null;
355
+ const settings: Record<string, unknown> = {};
356
+ for (const row of rows) {
357
+ try {
358
+ settings[row.key] = JSON.parse(row.value) as unknown;
359
+ } catch (error) {
360
+ logger.warn("AgentStorage failed to parse setting", {
361
+ key: row.key,
362
+ error: String(error),
363
+ });
364
+ }
365
+ }
366
+ return settings as Settings;
367
+ }
368
+
369
+ /**
370
+ * @deprecated Settings are now stored in config.yml, not agent.db.
371
+ * This method is kept for backward compatibility but does nothing.
372
+ */
373
+ saveSettings(settings: Settings): void {
374
+ logger.warn("AgentStorage.saveSettings is deprecated - settings are now stored in config.yml", {
375
+ keys: Object.keys(settings),
376
+ });
377
+ }
378
+
379
+ /**
380
+ * Gets a cached value by key. Returns null if not found or expired.
381
+ */
382
+ getCache(key: string): string | null {
383
+ try {
384
+ const row = this.#getCacheStmt.get(key) as { value?: string } | undefined;
385
+ return row?.value ?? null;
386
+ } catch {
387
+ return null;
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Sets a cached value with expiry time (unix seconds).
393
+ */
394
+ setCache(key: string, value: string, expiresAtSec: number): void {
395
+ try {
396
+ this.#upsertCacheStmt.run(key, value, expiresAtSec);
397
+ } catch (error) {
398
+ logger.warn("AgentStorage failed to set cache", { key, error: String(error) });
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Deletes expired cache entries. Call periodically for cleanup.
404
+ */
405
+ cleanExpiredCache(): void {
406
+ try {
407
+ this.#deleteExpiredCacheStmt.run();
408
+ } catch {
409
+ // Ignore cleanup errors
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Records model usage, updating the last-used timestamp.
415
+ * @param modelKey - Model key in "provider/modelId" format
416
+ */
417
+ recordModelUsage(modelKey: string): void {
418
+ try {
419
+ this.#upsertModelUsageStmt.run(modelKey);
420
+ this.#modelUsageCache = null;
421
+ } catch (error) {
422
+ logger.warn("AgentStorage failed to record model usage", { modelKey, error: String(error) });
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Gets model keys ordered by most recently used.
428
+ * Results are cached until recordModelUsage is called.
429
+ * @returns Array of model keys ("provider/modelId") in MRU order
430
+ */
431
+ getModelUsageOrder(): string[] {
432
+ if (this.#modelUsageCache) {
433
+ return this.#modelUsageCache;
434
+ }
435
+ try {
436
+ const rows = this.#listModelUsageStmt.all() as ModelUsageRow[];
437
+ this.#modelUsageCache = rows.map(row => row.model_key);
438
+ return this.#modelUsageCache;
439
+ } catch (error) {
440
+ logger.warn("AgentStorage failed to get model usage order", { error: String(error) });
441
+ return [];
442
+ }
443
+ }
444
+
445
+ /**
446
+ * Checks if any auth credentials exist in storage.
447
+ * @returns True if at least one credential is stored
448
+ */
449
+ hasAuthCredentials(): boolean {
450
+ const row = this.#countAuthStmt.get() as { count?: number } | undefined;
451
+ return (row?.count ?? 0) > 0;
452
+ }
453
+
454
+ /**
455
+ * Lists auth credentials, optionally filtered by provider.
456
+ * Only returns active (non-disabled) credentials by default.
457
+ * @param provider - Optional provider name to filter by
458
+ * @param includeDisabled - If true, includes disabled credentials
459
+ * @returns Array of stored credentials with their database IDs
460
+ */
461
+ listAuthCredentials(provider?: string, includeDisabled = false): StoredAuthCredential[] {
462
+ const rows = includeDisabled
463
+ ? ((provider
464
+ ? (this.#listAuthByProviderStmt.all(provider) as AuthRow[])
465
+ : (this.#listAuthStmt.all() as AuthRow[])) ?? [])
466
+ : ((provider
467
+ ? (this.#listActiveAuthByProviderStmt.all(provider) as AuthRow[])
468
+ : (this.#listActiveAuthStmt.all() as AuthRow[])) ?? []);
469
+
470
+ const results: StoredAuthCredential[] = [];
471
+ for (const row of rows) {
472
+ const credential = deserializeCredential(row);
473
+ if (!credential) continue;
474
+ results.push({ id: row.id, provider: row.provider, credential });
475
+ }
476
+ return results;
477
+ }
478
+
479
+ /**
480
+ * Atomically replaces all credentials for a provider.
481
+ * Useful for OAuth token refresh where old tokens should be discarded.
482
+ * @param provider - Provider name (e.g., "anthropic", "openai")
483
+ * @param credentials - New credentials to store
484
+ * @returns Array of newly stored credentials with their database IDs
485
+ */
486
+ replaceAuthCredentialsForProvider(provider: string, credentials: AuthCredential[]): StoredAuthCredential[] {
487
+ const replace = this.#db.transaction((providerName: string, items: AuthCredential[]) => {
488
+ this.#deleteAuthByProviderStmt.run(providerName);
489
+ const inserted: StoredAuthCredential[] = [];
490
+ for (const credential of items) {
491
+ const record = this.#insertAuthCredential(providerName, credential);
492
+ if (record) inserted.push(record);
493
+ }
494
+ return inserted;
495
+ });
496
+
497
+ return replace(provider, credentials);
498
+ }
499
+
500
+ /**
501
+ * Updates an existing auth credential by ID.
502
+ * @param id - Database row ID of the credential to update
503
+ * @param credential - New credential data
504
+ */
505
+ updateAuthCredential(id: number, credential: AuthCredential): void {
506
+ const serialized = serializeCredential(credential);
507
+ if (!serialized) {
508
+ logger.warn("AgentStorage updateAuthCredential invalid type", { id, type: credential.type });
509
+ return;
510
+ }
511
+ try {
512
+ this.#updateAuthStmt.run(serialized.credentialType, serialized.data, id);
513
+ } catch (error) {
514
+ logger.warn("AgentStorage updateAuthCredential failed", { id, error: String(error) });
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Deletes an auth credential by ID.
520
+ * @param id - Database row ID of the credential to delete
521
+ */
522
+ deleteAuthCredential(id: number): void {
523
+ try {
524
+ this.#deleteAuthStmt.run(id);
525
+ } catch (error) {
526
+ logger.warn("AgentStorage deleteAuthCredential failed", { id, error: String(error) });
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Disables an auth credential by ID (soft-delete).
532
+ * Disabled credentials are excluded from normal listing but remain in the database.
533
+ * @param id - Database row ID of the credential to disable
534
+ */
535
+ disableAuthCredential(id: number): void {
536
+ try {
537
+ this.#disableAuthStmt.run(id);
538
+ } catch (error) {
539
+ logger.warn("AgentStorage disableAuthCredential failed", { id, error: String(error) });
540
+ }
541
+ }
542
+
543
+ /**
544
+ * Deletes all auth credentials for a provider.
545
+ * @param provider - Provider name whose credentials should be deleted
546
+ */
547
+ deleteAuthCredentialsForProvider(provider: string): void {
548
+ try {
549
+ this.#deleteAuthByProviderStmt.run(provider);
550
+ } catch (error) {
551
+ logger.warn("AgentStorage deleteAuthCredentialsForProvider failed", {
552
+ provider,
553
+ error: String(error),
554
+ });
555
+ }
556
+ }
557
+
558
+ /**
559
+ * Inserts a new auth credential for a provider.
560
+ * @param provider - Provider name (e.g., "anthropic", "openai")
561
+ * @param credential - Credential to insert
562
+ * @returns Stored credential with database ID, or null on failure
563
+ */
564
+ #insertAuthCredential(provider: string, credential: AuthCredential): StoredAuthCredential | null {
565
+ const serialized = serializeCredential(credential);
566
+ if (!serialized) {
567
+ logger.warn("AgentStorage insertAuthCredential invalid type", { provider, type: credential.type });
568
+ return null;
569
+ }
570
+ try {
571
+ const row = this.#insertAuthStmt.get(provider, serialized.credentialType, serialized.data) as
572
+ | { id?: number }
573
+ | undefined;
574
+ if (!row?.id) {
575
+ logger.warn("AgentStorage insertAuthCredential missing id", { provider });
576
+ return null;
577
+ }
578
+ return { id: row.id, provider, credential };
579
+ } catch (error) {
580
+ logger.warn("AgentStorage insertAuthCredential failed", { provider, error: String(error) });
581
+ return null;
582
+ }
583
+ }
584
+
585
+ /**
586
+ * Ensures the parent directory for the database file exists.
587
+ * @param dbPath - Path to the database file
588
+ */
589
+ #ensureDir(dbPath: string): void {
590
+ const dir = path.dirname(dbPath);
591
+ try {
592
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
593
+ } catch (err) {
594
+ const code = (err as NodeJS.ErrnoException).code;
595
+ // EEXIST is fine - directory already exists
596
+ if (code !== "EEXIST") {
597
+ throw new Error(`Failed to create agent storage directory '${dir}': ${code || err}`);
598
+ }
599
+ }
600
+ // Verify directory was created
601
+ if (!fs.existsSync(dir)) {
602
+ throw new Error(`Agent storage directory '${dir}' does not exist after creation attempt`);
603
+ }
604
+ }
605
+
606
+ #hardenPermissions(dbPath: string): void {
607
+ const dir = path.dirname(dbPath);
608
+ try {
609
+ fs.chmodSync(dir, 0o700);
610
+ } catch (error) {
611
+ logger.warn("AgentStorage failed to chmod agent dir", { path: dir, error: String(error) });
612
+ }
613
+
614
+ if (!fs.existsSync(dbPath)) return;
615
+ try {
616
+ fs.chmodSync(dbPath, 0o600);
617
+ } catch (error) {
618
+ logger.warn("AgentStorage failed to chmod db file", { path: dbPath, error: String(error) });
619
+ }
620
+ }
621
+ }