akm-cli 0.8.2 → 0.9.0-beta.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 (316) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/dist/assets/help/help-proposals.md +1 -2
  3. package/dist/assets/hints/cli-hints-full.md +34 -19
  4. package/dist/assets/hints/cli-hints-short.md +1 -1
  5. package/dist/assets/profiles/catchup.json +13 -0
  6. package/dist/assets/profiles/consolidate.json +13 -0
  7. package/dist/assets/profiles/frequent.json +13 -0
  8. package/dist/assets/tasks/core/backup.yml +4 -0
  9. package/dist/assets/tasks/core/extract.yml +4 -0
  10. package/dist/assets/tasks/core/improve.yml +4 -0
  11. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  12. package/dist/assets/tasks/core/sync.yml +4 -0
  13. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  14. package/dist/assets/tasks/core/version-check.yml +4 -0
  15. package/dist/cli/config-migrate.js +6 -6
  16. package/dist/cli/config-validate.js +4 -4
  17. package/dist/cli/confirm.js +3 -3
  18. package/dist/cli/parse-args.js +1 -1
  19. package/dist/cli/shared.js +51 -14
  20. package/dist/cli-node.mjs +26 -0
  21. package/dist/cli.js +171 -3862
  22. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  23. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  24. package/dist/commands/agent/contribute-cli.js +200 -0
  25. package/dist/commands/completions.js +1 -1
  26. package/dist/commands/config-cli.js +240 -3
  27. package/dist/commands/config-edit.js +344 -0
  28. package/dist/commands/db-cli.js +2 -2
  29. package/dist/commands/env/env-cli.js +529 -0
  30. package/dist/commands/env/env.js +410 -0
  31. package/dist/commands/env/secret-cli.js +259 -0
  32. package/dist/commands/{secret.js → env/secret.js} +6 -47
  33. package/dist/commands/events.js +4 -4
  34. package/dist/commands/feedback-cli.js +18 -34
  35. package/dist/commands/graph/graph-cli.js +132 -0
  36. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  37. package/dist/commands/health/checks.js +279 -0
  38. package/dist/commands/health.js +94 -262
  39. package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
  40. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  41. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  42. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  43. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  44. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  45. package/dist/commands/{extract.js → improve/extract.js} +185 -26
  46. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +4 -4
  47. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
  48. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  49. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
  50. package/dist/commands/{improve.js → improve/improve.js} +509 -245
  51. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  52. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  53. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  54. package/dist/commands/{reflect.js → improve/reflect.js} +33 -28
  55. package/dist/commands/improve/session-asset.js +248 -0
  56. package/dist/commands/lint/agent-linter.js +1 -1
  57. package/dist/commands/lint/base-linter.js +55 -37
  58. package/dist/commands/lint/command-linter.js +1 -1
  59. package/dist/commands/lint/default-linter.js +1 -1
  60. package/dist/commands/lint/env-key-rules.js +1 -1
  61. package/dist/commands/lint/index.js +19 -25
  62. package/dist/commands/lint/knowledge-linter.js +1 -1
  63. package/dist/commands/lint/memory-linter.js +1 -1
  64. package/dist/commands/lint/registry.js +8 -8
  65. package/dist/commands/lint/skill-linter.js +1 -1
  66. package/dist/commands/lint/task-linter.js +1 -1
  67. package/dist/commands/lint/workflow-linter.js +1 -1
  68. package/dist/commands/lint.js +1 -1
  69. package/dist/commands/observability-cli.js +244 -0
  70. package/dist/commands/proposal/drain-policies.js +3 -3
  71. package/dist/commands/proposal/drain.js +15 -10
  72. package/dist/commands/proposal/proposal-cli.js +478 -0
  73. package/dist/commands/{proposal.js → proposal/proposal.js} +5 -5
  74. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  75. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  76. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  77. package/dist/{core → commands/proposal/validators}/proposals.js +13 -7
  78. package/dist/commands/{curate.js → read/curate.js} +7 -7
  79. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  80. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  81. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  82. package/dist/commands/read/search-cli.js +207 -0
  83. package/dist/commands/{search.js → read/search.js} +22 -27
  84. package/dist/commands/{show.js → read/show.js} +31 -45
  85. package/dist/commands/registry-cli.js +8 -8
  86. package/dist/commands/remember.js +8 -8
  87. package/dist/commands/sources/add-cli.js +293 -0
  88. package/dist/commands/{history.js → sources/history.js} +27 -25
  89. package/dist/commands/{info.js → sources/info.js} +6 -6
  90. package/dist/commands/{init.js → sources/init.js} +6 -6
  91. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  92. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  93. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  94. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  95. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  96. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  97. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  98. package/dist/commands/sources/sources-cli.js +305 -0
  99. package/dist/commands/sources/stash-cli.js +219 -0
  100. package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
  101. package/dist/commands/tasks/default-tasks.js +173 -0
  102. package/dist/commands/tasks/tasks-cli.js +210 -0
  103. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  104. package/dist/commands/wiki-cli.js +307 -0
  105. package/dist/commands/workflow-cli.js +329 -0
  106. package/dist/core/action-contributors.js +1 -1
  107. package/dist/core/assert.js +40 -0
  108. package/dist/core/asset/asset-create.js +54 -0
  109. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  110. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  111. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  112. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  113. package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
  114. package/dist/core/best-effort.js +64 -0
  115. package/dist/core/common.js +32 -18
  116. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  117. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  118. package/dist/core/{config-schema.js → config/config-schema.js} +45 -1
  119. package/dist/core/config/config-types.js +16 -0
  120. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  121. package/dist/core/{config.js → config/config.js} +10 -8
  122. package/dist/core/env-secret-ref.js +90 -0
  123. package/dist/core/errors.js +13 -3
  124. package/dist/core/events.js +27 -4
  125. package/dist/core/file-lock.js +1 -1
  126. package/dist/core/improve-types.js +48 -0
  127. package/dist/core/lesson-lint.js +2 -2
  128. package/dist/core/paths.js +2 -2
  129. package/dist/core/ripgrep/install.js +2 -2
  130. package/dist/core/ripgrep/resolve.js +2 -2
  131. package/dist/core/state-db.js +88 -46
  132. package/dist/core/text-truncation.js +148 -0
  133. package/dist/core/time.js +1 -1
  134. package/dist/core/write-source.js +98 -85
  135. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  136. package/dist/indexer/{db.js → db/db.js} +126 -116
  137. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  138. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  139. package/dist/indexer/ensure-index.js +4 -4
  140. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  141. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  142. package/dist/indexer/indexer.js +37 -30
  143. package/dist/indexer/init.js +54 -0
  144. package/dist/indexer/manifest.js +10 -10
  145. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +92 -23
  146. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  147. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  148. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  149. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  150. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  151. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  152. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  153. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  154. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  155. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  156. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  157. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  158. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  159. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  160. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  161. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  162. package/dist/integrations/agent/builder-shared.js +39 -0
  163. package/dist/integrations/agent/builders.js +14 -81
  164. package/dist/integrations/agent/config.js +6 -4
  165. package/dist/integrations/agent/detect.js +1 -1
  166. package/dist/integrations/agent/index.js +23 -8
  167. package/dist/integrations/agent/prompts.js +2 -3
  168. package/dist/integrations/agent/runner.js +22 -3
  169. package/dist/integrations/agent/spawn.js +9 -10
  170. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  171. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  172. package/dist/integrations/harnesses/claude/index.js +64 -0
  173. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +16 -1
  174. package/dist/integrations/harnesses/index.js +144 -0
  175. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  176. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  177. package/dist/integrations/harnesses/opencode/index.js +59 -0
  178. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  179. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  180. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  181. package/dist/integrations/harnesses/types.js +43 -0
  182. package/dist/integrations/lockfile.js +7 -16
  183. package/dist/integrations/session-logs/index.js +82 -9
  184. package/dist/llm/call-ai.js +4 -4
  185. package/dist/llm/client.js +131 -6
  186. package/dist/llm/embedder.js +6 -6
  187. package/dist/llm/embedders/local.js +9 -22
  188. package/dist/llm/embedders/remote.js +2 -2
  189. package/dist/llm/embedders/types.js +1 -1
  190. package/dist/llm/graph-extract.js +31 -12
  191. package/dist/llm/index-passes.js +1 -1
  192. package/dist/llm/memory-infer.js +12 -5
  193. package/dist/llm/metadata-enhance.js +2 -2
  194. package/dist/output/context.js +6 -44
  195. package/dist/output/renderers.js +88 -58
  196. package/dist/output/shapes/curate.js +7 -3
  197. package/dist/output/shapes/distill.js +7 -3
  198. package/dist/output/shapes/env-list.js +18 -16
  199. package/dist/output/shapes/events.js +5 -4
  200. package/dist/output/shapes/helpers.js +2 -4
  201. package/dist/output/shapes/history.js +7 -3
  202. package/dist/output/shapes/passthrough.js +8 -11
  203. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  204. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  205. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  206. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  207. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  208. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  209. package/dist/output/shapes/registry-search.js +7 -3
  210. package/dist/output/shapes/registry.js +12 -0
  211. package/dist/output/shapes/search.js +7 -3
  212. package/dist/output/shapes/secret-list.js +18 -16
  213. package/dist/output/shapes/show.js +7 -3
  214. package/dist/output/shapes.js +55 -30
  215. package/dist/output/text/add.js +2 -3
  216. package/dist/output/text/clone.js +2 -3
  217. package/dist/output/text/config.js +2 -3
  218. package/dist/output/text/curate.js +4 -3
  219. package/dist/output/text/distill.js +2 -3
  220. package/dist/output/text/enable-disable.js +5 -4
  221. package/dist/output/text/env.js +13 -0
  222. package/dist/output/text/events.js +5 -4
  223. package/dist/output/text/feedback.js +4 -3
  224. package/dist/output/text/helpers.js +54 -39
  225. package/dist/output/text/history.js +2 -3
  226. package/dist/output/text/import.js +2 -3
  227. package/dist/output/text/index.js +2 -3
  228. package/dist/output/text/info.js +2 -3
  229. package/dist/output/text/init.js +2 -3
  230. package/dist/output/text/list.js +2 -3
  231. package/dist/output/text/proposal/producer.js +9 -0
  232. package/dist/output/text/proposal/proposal.js +13 -0
  233. package/dist/output/text/registry-commands.js +8 -7
  234. package/dist/output/text/registry.js +12 -0
  235. package/dist/output/text/remember.js +4 -3
  236. package/dist/output/text/remove.js +2 -3
  237. package/dist/output/text/save.js +2 -3
  238. package/dist/output/text/search.js +4 -3
  239. package/dist/output/text/show.js +4 -3
  240. package/dist/output/text/update.js +2 -3
  241. package/dist/output/text/upgrade.js +2 -3
  242. package/dist/output/text/wiki.js +12 -11
  243. package/dist/output/text/workflow.js +12 -10
  244. package/dist/output/text.js +66 -32
  245. package/dist/registry/build-index.js +11 -10
  246. package/dist/registry/factory.js +1 -1
  247. package/dist/registry/origin-resolve.js +1 -1
  248. package/dist/registry/providers/index.js +2 -2
  249. package/dist/registry/providers/skills-sh.js +91 -72
  250. package/dist/registry/providers/static-index.js +75 -52
  251. package/dist/registry/resolve.js +3 -3
  252. package/dist/runtime.js +242 -0
  253. package/dist/scripts/migrate-storage.js +1594 -673
  254. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +240 -166
  255. package/dist/setup/detect.js +311 -9
  256. package/dist/setup/harness-config-import.js +6 -120
  257. package/dist/setup/setup.js +454 -43
  258. package/dist/sources/include.js +1 -1
  259. package/dist/sources/provider-factory.js +2 -2
  260. package/dist/sources/providers/filesystem.js +3 -3
  261. package/dist/sources/providers/git.js +9 -9
  262. package/dist/sources/providers/index.js +4 -4
  263. package/dist/sources/providers/npm.js +6 -6
  264. package/dist/sources/providers/provider-utils.js +13 -20
  265. package/dist/sources/providers/sync-from-ref.js +5 -5
  266. package/dist/sources/providers/tar-utils.js +2 -2
  267. package/dist/sources/providers/website.js +2 -2
  268. package/dist/sources/resolve.js +5 -5
  269. package/dist/sources/website-ingest.js +5 -5
  270. package/dist/storage/database.js +102 -0
  271. package/dist/storage/engines/sqlite-migrations.js +42 -0
  272. package/dist/storage/locations.js +25 -0
  273. package/dist/storage/repositories/index-db.js +43 -0
  274. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  275. package/dist/tasks/backends/cron.js +4 -4
  276. package/dist/tasks/backends/exec-utils.js +32 -0
  277. package/dist/tasks/backends/index.js +3 -3
  278. package/dist/tasks/backends/launchd.js +7 -14
  279. package/dist/tasks/backends/schtasks.js +7 -16
  280. package/dist/tasks/embedded.js +71 -0
  281. package/dist/tasks/parser.js +2 -2
  282. package/dist/tasks/resolveAkmBin.js +1 -1
  283. package/dist/tasks/runner.js +28 -15
  284. package/dist/tasks/schedule.js +1 -1
  285. package/dist/tasks/validator.js +7 -7
  286. package/dist/text-import-hook.mjs +51 -0
  287. package/dist/version.js +2 -1
  288. package/dist/wiki/wiki.js +7 -7
  289. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  290. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  291. package/dist/workflows/cli.js +1 -1
  292. package/dist/workflows/db.js +50 -32
  293. package/dist/workflows/parser.js +4 -4
  294. package/dist/workflows/renderer.js +5 -5
  295. package/dist/workflows/runtime/agent-identity.js +56 -0
  296. package/dist/workflows/runtime/checkin.js +57 -0
  297. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  298. package/dist/workflows/validate-summary.js +82 -0
  299. package/docs/README.md +1 -1
  300. package/docs/data-and-telemetry.md +6 -6
  301. package/package.json +16 -8
  302. package/dist/commands/add-cli.js +0 -279
  303. package/dist/commands/env.js +0 -213
  304. package/dist/integrations/agent/sdk-runner.js +0 -126
  305. package/dist/output/shapes/vault-list.js +0 -19
  306. package/dist/output/text/proposal-producer.js +0 -8
  307. package/dist/output/text/proposal.js +0 -12
  308. package/dist/output/text/vault.js +0 -16
  309. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  310. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  311. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  312. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  313. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  314. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  315. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  316. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -384,7 +384,73 @@ var require_main = __commonJS((exports, module) => {
384
384
  module.exports = DotenvModule;
385
385
  });
386
386
 
387
- // src/commands/env.ts
387
+ // src/core/errors.ts
388
+ function isTestIsolationError(err) {
389
+ return err instanceof ConfigError && err.code === "TEST_ISOLATION_MISSING";
390
+ }
391
+ function rethrowIfTestIsolationError(err) {
392
+ if (isTestIsolationError(err)) {
393
+ throw err;
394
+ }
395
+ }
396
+ var CONFIG_HINTS, USAGE_HINTS, AkmError, ConfigError, UsageError;
397
+ var init_errors = __esm(() => {
398
+ CONFIG_HINTS = {
399
+ STASH_DIR_NOT_FOUND: "Run `akm setup` to create and configure your stash, or set stashDir in your config.",
400
+ STASH_DIR_NOT_A_DIRECTORY: "The configured stashDir exists but isn't a directory. Update stashDir to point at a folder.",
401
+ STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update stashDir.",
402
+ EMBEDDING_NOT_CONFIGURED: 'Run `akm config set embedding \'{"endpoint":"...","model":"..."}\'` to enable embeddings.',
403
+ LLM_NOT_CONFIGURED: 'Run `akm setup` or `akm config set profiles.llm.default \'{"endpoint":"...","model":"..."}\' to configure an LLM profile.',
404
+ TEST_ISOLATION_MISSING: "Under bun test, when AKM_STASH_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
405
+ SETUP_TMP_STASH_REFUSED: "Use a persistent directory, or set AKM_FORCE_SETUP_TMP_STASH=1 to opt in to a sandboxed setup (setup also pre-sets AKM_STASH_DIR so config and cache writes auto-isolate into $stashDir/.akm/ \u2014 host config is preserved).",
406
+ UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The stash directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh."
407
+ };
408
+ USAGE_HINTS = {
409
+ INVALID_FLAG_VALUE: "Run `akm <command> --help` to see accepted values.",
410
+ INVALID_SOURCE_VALUE: "Pick one of: stash, registry, both.",
411
+ INVALID_FORMAT_VALUE: "Pick one of: json, jsonl, text, yaml.",
412
+ INVALID_DETAIL_VALUE: "Pick one of: brief, normal, full. For agent/summary projections use --shape.",
413
+ INVALID_SHAPE_VALUE: "Pick one of: human, agent, summary (summary is only valid on `akm show`).",
414
+ INVALID_JSON_CONFIG_VALUE: `Quote JSON values in your shell, for example: akm config set embedding '{"endpoint":"http://localhost:11434/v1/embeddings","model":"nomic-embed-text"}'.`,
415
+ MISSING_OR_AMBIGUOUS_TARGET: "Use `akm update --all` or pass a target like `akm update npm:@scope/pkg` (not both).",
416
+ TARGET_NOT_UPDATABLE: "Run `akm list` to view your sources, then retry with one of those values.",
417
+ MISSING_REQUIRED_ARGUMENT: "Refs use the form type:name, e.g. `akm show skill:deploy` or `akm show knowledge:guide.md`."
418
+ };
419
+ AkmError = class AkmError extends Error {
420
+ };
421
+ ConfigError = class ConfigError extends AkmError {
422
+ kind = "config";
423
+ code;
424
+ _hint;
425
+ constructor(msg, code = "INVALID_CONFIG_FILE", hint) {
426
+ super(msg);
427
+ this.name = "ConfigError";
428
+ this.code = code;
429
+ this._hint = hint;
430
+ Object.setPrototypeOf(this, new.target.prototype);
431
+ }
432
+ hint() {
433
+ return this._hint ?? CONFIG_HINTS[this.code];
434
+ }
435
+ };
436
+ UsageError = class UsageError extends AkmError {
437
+ kind = "usage";
438
+ code;
439
+ _hint;
440
+ constructor(msg, code = "INVALID_FLAG_VALUE", hint) {
441
+ super(msg);
442
+ this.name = "UsageError";
443
+ this.code = code;
444
+ this._hint = hint;
445
+ Object.setPrototypeOf(this, new.target.prototype);
446
+ }
447
+ hint() {
448
+ return this._hint ?? USAGE_HINTS[this.code];
449
+ }
450
+ };
451
+ });
452
+
453
+ // src/commands/env/env.ts
388
454
  import fs from "fs";
389
455
  function scanKeys(text) {
390
456
  const keys = [];
@@ -420,11 +486,12 @@ function listKeys(envPath) {
420
486
  var import_dotenv, ASSIGN_RE;
421
487
  var init_env = __esm(() => {
422
488
  init_common();
489
+ init_errors();
423
490
  import_dotenv = __toESM(require_main(), 1);
424
491
  ASSIGN_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
425
492
  });
426
493
 
427
- // src/core/frontmatter.ts
494
+ // src/core/asset/frontmatter.ts
428
495
  function parseFrontmatter(raw) {
429
496
  const parsedBlock = parseFrontmatterBlock(raw);
430
497
  if (!parsedBlock) {
@@ -572,7 +639,7 @@ function parseYamlScalar(value) {
572
639
  return value;
573
640
  }
574
641
 
575
- // src/core/markdown.ts
642
+ // src/core/asset/markdown.ts
576
643
  function parseMarkdownToc(content) {
577
644
  const lines = content.split(/\r?\n/);
578
645
  const headings = [];
@@ -592,15 +659,16 @@ function parseMarkdownToc(content) {
592
659
  }
593
660
  var init_markdown = () => {};
594
661
 
595
- // src/indexer/file-context.ts
596
- var renderers;
597
- var init_file_context = __esm(() => {
598
- init_common();
599
- renderers = new Map;
600
- });
601
-
602
662
  // src/core/warn.ts
603
663
  import fs2 from "fs";
664
+ function isVerbose() {
665
+ const env = process.env.AKM_VERBOSE?.trim().toLowerCase();
666
+ if (env === "1" || env === "true" || env === "yes" || env === "on")
667
+ return true;
668
+ if (env === "0" || env === "false" || env === "no" || env === "off")
669
+ return false;
670
+ return verbose;
671
+ }
604
672
  function appendToLogFile(level, args) {
605
673
  if (!logFilePath)
606
674
  return;
@@ -628,10 +696,22 @@ function error(...args) {
628
696
  console.error(...args);
629
697
  }
630
698
  }
631
- var quiet = false, logFilePath;
699
+ function warnVerbose(...args) {
700
+ if (isVerbose()) {
701
+ warn(...args);
702
+ }
703
+ }
704
+ var quiet = false, verbose = false, logFilePath;
632
705
  var init_warn = () => {};
633
706
 
634
- // src/indexer/metadata-contributors.ts
707
+ // src/indexer/walk/file-context.ts
708
+ var renderers;
709
+ var init_file_context = __esm(() => {
710
+ init_common();
711
+ renderers = new Map;
712
+ });
713
+
714
+ // src/indexer/passes/metadata-contributors.ts
635
715
  function registerMetadataContributor(contributor) {
636
716
  contributors.push(contributor);
637
717
  }
@@ -640,7 +720,7 @@ var init_metadata_contributors = __esm(() => {
640
720
  contributors = [];
641
721
  });
642
722
 
643
- // src/indexer/metadata.ts
723
+ // src/indexer/passes/metadata.ts
644
724
  import fs3 from "fs";
645
725
  function extractDescriptionFromComments(filePath) {
646
726
  let content;
@@ -692,69 +772,7 @@ var init_metadata = __esm(() => {
692
772
  WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
693
773
  });
694
774
 
695
- // src/core/errors.ts
696
- function isTestIsolationError(err) {
697
- return err instanceof ConfigError && err.code === "TEST_ISOLATION_MISSING";
698
- }
699
- function rethrowIfTestIsolationError(err) {
700
- if (isTestIsolationError(err)) {
701
- throw err;
702
- }
703
- }
704
- var CONFIG_HINTS, USAGE_HINTS, ConfigError, UsageError;
705
- var init_errors = __esm(() => {
706
- CONFIG_HINTS = {
707
- STASH_DIR_NOT_FOUND: "Run `akm setup` to create and configure your stash, or set stashDir in your config.",
708
- STASH_DIR_NOT_A_DIRECTORY: "The configured stashDir exists but isn't a directory. Update stashDir to point at a folder.",
709
- STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update stashDir.",
710
- EMBEDDING_NOT_CONFIGURED: 'Run `akm config set embedding \'{"endpoint":"...","model":"..."}\'` to enable embeddings.',
711
- LLM_NOT_CONFIGURED: 'Run `akm setup` or `akm config set profiles.llm.default \'{"endpoint":"...","model":"..."}\' to configure an LLM profile.',
712
- TEST_ISOLATION_MISSING: "Under bun test, when AKM_STASH_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
713
- SETUP_TMP_STASH_REFUSED: "Use a persistent directory, or set AKM_FORCE_SETUP_TMP_STASH=1 to opt in to a sandboxed setup (setup also pre-sets AKM_STASH_DIR so config and cache writes auto-isolate into $stashDir/.akm/ \u2014 host config is preserved).",
714
- UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The stash directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh."
715
- };
716
- USAGE_HINTS = {
717
- INVALID_FLAG_VALUE: "Run `akm <command> --help` to see accepted values.",
718
- INVALID_SOURCE_VALUE: "Pick one of: stash, registry, both.",
719
- INVALID_FORMAT_VALUE: "Pick one of: json, jsonl, text, yaml.",
720
- INVALID_DETAIL_VALUE: "Pick one of: brief, normal, full. For agent/summary projections use --shape.",
721
- INVALID_SHAPE_VALUE: "Pick one of: human, agent, summary (summary is only valid on `akm show`).",
722
- INVALID_JSON_CONFIG_VALUE: `Quote JSON values in your shell, for example: akm config set embedding '{"endpoint":"http://localhost:11434/v1/embeddings","model":"nomic-embed-text"}'.`,
723
- MISSING_OR_AMBIGUOUS_TARGET: "Use `akm update --all` or pass a target like `akm update npm:@scope/pkg` (not both).",
724
- TARGET_NOT_UPDATABLE: "Run `akm list` to view your sources, then retry with one of those values.",
725
- MISSING_REQUIRED_ARGUMENT: "Refs use the form type:name, e.g. `akm show skill:deploy` or `akm show knowledge:guide.md`."
726
- };
727
- ConfigError = class ConfigError extends Error {
728
- code;
729
- _hint;
730
- constructor(msg, code = "INVALID_CONFIG_FILE", hint) {
731
- super(msg);
732
- this.name = "ConfigError";
733
- this.code = code;
734
- this._hint = hint;
735
- Object.setPrototypeOf(this, new.target.prototype);
736
- }
737
- hint() {
738
- return this._hint ?? CONFIG_HINTS[this.code];
739
- }
740
- };
741
- UsageError = class UsageError extends Error {
742
- code;
743
- _hint;
744
- constructor(msg, code = "INVALID_FLAG_VALUE", hint) {
745
- super(msg);
746
- this.name = "UsageError";
747
- this.code = code;
748
- this._hint = hint;
749
- Object.setPrototypeOf(this, new.target.prototype);
750
- }
751
- hint() {
752
- return this._hint ?? USAGE_HINTS[this.code];
753
- }
754
- };
755
- });
756
-
757
- // src/core/asset-ref.ts
775
+ // src/core/asset/asset-ref.ts
758
776
  import path from "path";
759
777
  function parseAssetRef(ref) {
760
778
  const trimmed = ref.trim();
@@ -775,6 +793,9 @@ function parseAssetRef(ref) {
775
793
  }
776
794
  const rawType = body.slice(0, colon);
777
795
  const rawName = body.slice(colon + 1);
796
+ if (rawType === "vault") {
797
+ throw new UsageError("The `vault` asset type was removed in 0.9.0 \u2014 use `env:` (whole .env config) or `secret:` (a single value).", "MISSING_REQUIRED_ARGUMENT");
798
+ }
778
799
  const resolvedType = TYPE_ALIASES[rawType] ?? rawType;
779
800
  if (!isAssetType(resolvedType)) {
780
801
  throw new UsageError(`Invalid asset type: "${rawType}".`, "MISSING_REQUIRED_ARGUMENT");
@@ -813,15 +834,6 @@ var init_asset_ref = __esm(() => {
813
834
  };
814
835
  });
815
836
 
816
- // src/workflows/document-cache.ts
817
- function cacheWorkflowDocument(entry, doc) {
818
- cache.set(entry, doc);
819
- }
820
- var cache;
821
- var init_document_cache = __esm(() => {
822
- cache = new WeakMap;
823
- });
824
-
825
837
  // node_modules/yaml/dist/nodes/identity.js
826
838
  var require_identity = __commonJS((exports) => {
827
839
  var ALIAS = Symbol.for("yaml.alias");
@@ -8192,6 +8204,15 @@ var init_parser = __esm(() => {
8192
8204
  BULLET_LINE = /^[-*]\s+(.+)$/;
8193
8205
  });
8194
8206
 
8207
+ // src/workflows/runtime/document-cache.ts
8208
+ function cacheWorkflowDocument(entry, doc) {
8209
+ cache.set(entry, doc);
8210
+ }
8211
+ var cache;
8212
+ var init_document_cache = __esm(() => {
8213
+ cache = new WeakMap;
8214
+ });
8215
+
8195
8216
  // src/workflows/renderer.ts
8196
8217
  function shellQuote(value) {
8197
8218
  return `'${value.replace(/'/g, `'\\''`)}'`;
@@ -8212,8 +8233,8 @@ var init_renderer = __esm(() => {
8212
8233
  init_asset_ref();
8213
8234
  init_errors();
8214
8235
  init_metadata_contributors();
8215
- init_document_cache();
8216
8236
  init_parser();
8237
+ init_document_cache();
8217
8238
  registerMetadataContributor({
8218
8239
  name: "workflow-document-metadata",
8219
8240
  appliesTo: ({ rendererName }) => rendererName === "workflow-md",
@@ -8242,6 +8263,24 @@ var init_renderer = __esm(() => {
8242
8263
  });
8243
8264
 
8244
8265
  // src/output/renderers.ts
8266
+ function applySessionMetadata(entry, ctx) {
8267
+ try {
8268
+ const fm = applyFrontmatterDescriptionAndTags(entry, ctx);
8269
+ entry.tags = Array.from(new Set([...entry.tags ?? [], "session"]));
8270
+ const hints = new Set(entry.searchHints ?? []);
8271
+ const harness = asNonEmptyString(fm.harness);
8272
+ if (harness)
8273
+ hints.add(`harness:${harness}`);
8274
+ const project = asNonEmptyString(fm.project);
8275
+ if (project)
8276
+ hints.add(`project:${project}`);
8277
+ const logPath = asNonEmptyString(fm.log_path);
8278
+ if (logPath)
8279
+ hints.add(`log_path:${logPath}`);
8280
+ if (hints.size > 0)
8281
+ entry.searchHints = Array.from(hints).filter(Boolean);
8282
+ } catch {}
8283
+ }
8245
8284
  function applyTocMetadata(entry, ctx) {
8246
8285
  try {
8247
8286
  const toc = parseMarkdownToc(ctx.content());
@@ -8313,18 +8352,6 @@ function applyScriptMetadata(entry, ctx) {
8313
8352
  entry.confidence = 0.7;
8314
8353
  }
8315
8354
  }
8316
- function applyVaultMetadata(entry, ctx) {
8317
- const { keys, comments } = listKeys(ctx.absPath);
8318
- if (comments.length > 0 && !entry.description) {
8319
- entry.description = comments.join(" ").slice(0, 500);
8320
- entry.source = "comments";
8321
- entry.confidence = 0.7;
8322
- }
8323
- if (keys.length > 0) {
8324
- entry.searchHints = keys;
8325
- }
8326
- entry.tags = Array.from(new Set([...entry.tags ?? [], "vault", "secrets"]));
8327
- }
8328
8355
  function applyEnvMetadata(entry, ctx) {
8329
8356
  const { keys, comments } = listKeys(ctx.absPath);
8330
8357
  if (comments.length > 0 && !entry.description) {
@@ -8360,11 +8387,11 @@ function applyTaskMetadata(entry, ctx) {
8360
8387
  }
8361
8388
  var init_renderers = __esm(() => {
8362
8389
  init_env();
8363
- init_common();
8364
8390
  init_markdown();
8365
- init_file_context();
8391
+ init_common();
8366
8392
  init_metadata();
8367
8393
  init_metadata_contributors();
8394
+ init_file_context();
8368
8395
  init_renderer();
8369
8396
  registerMetadataContributor({
8370
8397
  name: "toc-metadata",
@@ -8386,11 +8413,6 @@ var init_renderers = __esm(() => {
8386
8413
  appliesTo: ({ rendererName }) => rendererName === "script-source",
8387
8414
  contribute: (entry, ctx) => applyScriptMetadata(entry, ctx.renderContext)
8388
8415
  });
8389
- registerMetadataContributor({
8390
- name: "vault-secret-metadata",
8391
- appliesTo: ({ rendererName }) => rendererName === "vault-env",
8392
- contribute: (entry, ctx) => applyVaultMetadata(entry, ctx.renderContext)
8393
- });
8394
8416
  registerMetadataContributor({
8395
8417
  name: "env-file-metadata",
8396
8418
  appliesTo: ({ rendererName }) => rendererName === "env-file",
@@ -8406,20 +8428,28 @@ var init_renderers = __esm(() => {
8406
8428
  appliesTo: ({ rendererName }) => rendererName === "task-yaml",
8407
8429
  contribute: (entry, ctx) => applyTaskMetadata(entry, ctx.renderContext)
8408
8430
  });
8431
+ registerMetadataContributor({
8432
+ name: "session-md-metadata",
8433
+ appliesTo: ({ rendererName }) => rendererName === "session-md",
8434
+ contribute: (entry, ctx) => applySessionMetadata(entry, ctx.renderContext)
8435
+ });
8409
8436
  });
8410
8437
 
8411
- // src/core/asset-registry.ts
8438
+ // src/core/asset/asset-registry.ts
8412
8439
  var init_asset_registry = __esm(() => {
8413
8440
  init_renderers();
8414
8441
  });
8415
8442
 
8416
- // src/core/asset-spec.ts
8443
+ // src/core/asset/asset-spec.ts
8417
8444
  import path2 from "path";
8445
+ function getAssetTypes() {
8446
+ return Object.keys(ASSET_SPECS_INTERNAL);
8447
+ }
8418
8448
  var buildTaskAction = (ref) => `akm tasks show ${ref.replace(/^task:/, "")} -> inspect; akm tasks run <id> -> run now; akm tasks remove <id> -> unschedule`, markdownSpec, SCRIPT_EXTENSIONS, scriptSpec, ASSET_SPECS_INTERNAL, TYPE_DIRS;
8419
8449
  var init_asset_spec = __esm(() => {
8420
8450
  init_renderers();
8421
- init_asset_registry();
8422
8451
  init_common();
8452
+ init_asset_registry();
8423
8453
  markdownSpec = {
8424
8454
  isRelevantFile: (fileName) => path2.extname(fileName).toLowerCase() === ".md",
8425
8455
  toCanonicalName: (typeRoot, filePath) => {
@@ -8498,27 +8528,6 @@ var init_asset_spec = __esm(() => {
8498
8528
  rendererName: "env-file",
8499
8529
  actionBuilder: (ref) => `akm show ${ref} -> inspect key names; akm env run ${ref} -- <command> -> run with the whole .env injected (values never reach stdout); akm env export ${ref} --out <file> -> write a sourceable script to a file`
8500
8530
  },
8501
- vault: {
8502
- stashDir: "vaults",
8503
- isRelevantFile: (fileName) => fileName === ".env" || fileName.endsWith(".env"),
8504
- toCanonicalName: (typeRoot, filePath) => {
8505
- const rel = toPosix(path2.relative(typeRoot, filePath));
8506
- const fileName = path2.basename(rel);
8507
- if (fileName === ".env") {
8508
- const dir = path2.dirname(rel);
8509
- return dir === "." || dir === "" ? "default" : `${dir}/default`;
8510
- }
8511
- const stripped = rel.endsWith(".env") ? rel.slice(0, -4) : rel;
8512
- return stripped;
8513
- },
8514
- toAssetPath: (typeRoot, name) => {
8515
- if (name === "default")
8516
- return path2.join(typeRoot, ".env");
8517
- return path2.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8518
- },
8519
- rendererName: "vault-env",
8520
- actionBuilder: (ref) => `DEPRECATED (use env): akm show ${ref} -> inspect key names; akm env run ${ref} -- <command> -> run with injected env`
8521
- },
8522
8531
  secret: {
8523
8532
  stashDir: "secrets",
8524
8533
  isRelevantFile: (fileName) => !fileName.endsWith(".lock") && !fileName.endsWith(".sensitive"),
@@ -8552,6 +8561,12 @@ var init_asset_spec = __esm(() => {
8552
8561
  },
8553
8562
  rendererName: "task-yaml",
8554
8563
  actionBuilder: buildTaskAction
8564
+ },
8565
+ session: {
8566
+ stashDir: "sessions",
8567
+ ...markdownSpec,
8568
+ rendererName: "session-md",
8569
+ actionBuilder: (ref) => `akm show ${ref} -> read the session summary; follow the \`access\` frontmatter to open the raw log at \`log_path\``
8555
8570
  }
8556
8571
  };
8557
8572
  TYPE_DIRS = Object.fromEntries(Object.entries(ASSET_SPECS_INTERNAL).map(([type, spec]) => [type, spec.stashDir]));
@@ -8568,7 +8583,11 @@ function writeFileAtomic(target, content, mode) {
8568
8583
  const tmp = `${target}.tmp.${process.pid}.${crypto.randomBytes(8).toString("hex")}`;
8569
8584
  const fd = fs4.openSync(tmp, "w", mode ?? 384);
8570
8585
  try {
8571
- fs4.writeSync(fd, content);
8586
+ if (typeof content === "string") {
8587
+ fs4.writeSync(fd, content);
8588
+ } else {
8589
+ fs4.writeSync(fd, content);
8590
+ }
8572
8591
  try {
8573
8592
  fs4.fdatasyncSync(fd);
8574
8593
  } catch {}
@@ -8607,20 +8626,7 @@ var init_common = __esm(() => {
8607
8626
  init_asset_spec();
8608
8627
  init_errors();
8609
8628
  init_paths();
8610
- ASSET_TYPES = [
8611
- "skill",
8612
- "command",
8613
- "agent",
8614
- "knowledge",
8615
- "workflow",
8616
- "script",
8617
- "memory",
8618
- "env",
8619
- "vault",
8620
- "secret",
8621
- "wiki",
8622
- "lesson"
8623
- ];
8629
+ ASSET_TYPES = Object.freeze([...getAssetTypes()]);
8624
8630
  ASSET_TYPE_SET = new Set(ASSET_TYPES);
8625
8631
  IS_WINDOWS = process.platform === "win32";
8626
8632
  DEFAULT_RESPONSE_BYTE_CAP = 10 * 1024 * 1024;
@@ -8760,55 +8766,58 @@ var init_paths = __esm(() => {
8760
8766
  init_errors();
8761
8767
  });
8762
8768
 
8763
- // src/core/state-db.ts
8764
- var exports_state_db = {};
8765
- __export(exports_state_db, {
8766
- upsertTaskHistory: () => upsertTaskHistory,
8767
- upsertProposal: () => upsertProposal,
8768
- upsertExtractedSession: () => upsertExtractedSession,
8769
- shouldSkipAlreadyExtractedSession: () => shouldSkipAlreadyExtractedSession,
8770
- runMigrations: () => runMigrations,
8771
- recordImproveRun: () => recordImproveRun,
8772
- readStateEvents: () => readStateEvents,
8773
- queryTaskHistory: () => queryTaskHistory,
8774
- purgeOldImproveRuns: () => purgeOldImproveRuns,
8775
- purgeOldEvents: () => purgeOldEvents,
8776
- proposalToRowValues: () => proposalToRowValues,
8777
- proposalRowToProposal: () => proposalRowToProposal,
8778
- openStateDatabase: () => openStateDatabase,
8779
- listStateProposals: () => listStateProposals,
8780
- insertEvent: () => insertEvent,
8781
- importEventsJsonl: () => importEventsJsonl,
8782
- getTaskHistoryRuns: () => getTaskHistoryRuns,
8783
- getTaskHistory: () => getTaskHistory,
8784
- getStateProposal: () => getStateProposal,
8785
- getStateDbPath: () => getStateDbPath,
8786
- getExtractedSessionsMap: () => getExtractedSessionsMap,
8787
- getExtractedSession: () => getExtractedSession,
8788
- eventRowToEnvelope: () => eventRowToEnvelope,
8789
- computeImproveRunMetrics: () => computeImproveRunMetrics,
8790
- REGISTRY_INDEX_CACHE_DDL: () => REGISTRY_INDEX_CACHE_DDL
8791
- });
8792
- import { Database } from "bun:sqlite";
8793
- import fs5 from "fs";
8794
- import path5 from "path";
8795
- function getStateDbPath() {
8796
- return path5.join(getDataDir(), "state.db");
8797
- }
8798
- function openStateDatabase(dbPath) {
8799
- const resolvedPath = dbPath ?? getStateDbPath();
8800
- const dir = path5.dirname(resolvedPath);
8801
- if (!fs5.existsSync(dir)) {
8802
- fs5.mkdirSync(dir, { recursive: true });
8769
+ // src/storage/database.ts
8770
+ import { createRequire } from "module";
8771
+ function openDatabase(path5, opts) {
8772
+ if (isBun) {
8773
+ return openBunDatabase(path5, opts);
8803
8774
  }
8804
- const db = new Database(resolvedPath);
8805
- db.exec("PRAGMA journal_mode = WAL");
8806
- db.exec("PRAGMA foreign_keys = ON");
8807
- db.exec("PRAGMA busy_timeout = 5000");
8808
- runMigrations(db);
8775
+ return openNodeDatabase(path5, opts);
8776
+ }
8777
+ function openBunDatabase(path5, opts) {
8778
+ const { Database: BunDatabase } = loadBunSqlite();
8779
+ const db = opts ? new BunDatabase(path5, bunOptions(opts)) : new BunDatabase(path5);
8809
8780
  return db;
8810
8781
  }
8811
- function ensureMigrationsTable(db) {
8782
+ function bunOptions(opts) {
8783
+ const out = {};
8784
+ if (opts.readonly !== undefined)
8785
+ out.readonly = opts.readonly;
8786
+ if (opts.create !== undefined)
8787
+ out.create = opts.create;
8788
+ return out;
8789
+ }
8790
+ function loadBunSqlite() {
8791
+ if (!bunSqliteModule) {
8792
+ bunSqliteModule = nodeRequire("bun:sqlite");
8793
+ }
8794
+ return bunSqliteModule;
8795
+ }
8796
+ function loadBetterSqlite3() {
8797
+ if (!betterSqlite3Ctor) {
8798
+ const mod = nodeRequire("better-sqlite3");
8799
+ betterSqlite3Ctor = mod.default ?? mod;
8800
+ }
8801
+ return betterSqlite3Ctor;
8802
+ }
8803
+ function openNodeDatabase(path5, opts) {
8804
+ const BetterSqlite3 = loadBetterSqlite3();
8805
+ const options = {};
8806
+ if (opts?.readonly !== undefined)
8807
+ options.readonly = opts.readonly;
8808
+ if (opts?.create === false)
8809
+ options.fileMustExist = true;
8810
+ const db = opts ? new BetterSqlite3(path5, options) : new BetterSqlite3(path5);
8811
+ return db;
8812
+ }
8813
+ var isBun, nodeRequire, bunSqliteModule, betterSqlite3Ctor;
8814
+ var init_database = __esm(() => {
8815
+ isBun = !!process.versions?.bun;
8816
+ nodeRequire = createRequire(import.meta.url);
8817
+ });
8818
+
8819
+ // src/storage/engines/sqlite-migrations.ts
8820
+ function ensureMigrationsTable(db) {
8812
8821
  db.exec(`
8813
8822
  CREATE TABLE IF NOT EXISTS schema_migrations (
8814
8823
  id TEXT PRIMARY KEY,
@@ -8816,11 +8825,12 @@ function ensureMigrationsTable(db) {
8816
8825
  );
8817
8826
  `);
8818
8827
  }
8819
- function runMigrations(db) {
8828
+ function runMigrations(db, migrations, opts) {
8820
8829
  ensureMigrationsTable(db);
8830
+ opts?.bootstrap?.(db);
8821
8831
  const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
8822
8832
  const applied = new Set(appliedRows.map((r) => r.id));
8823
- for (const migration of MIGRATIONS) {
8833
+ for (const migration of migrations) {
8824
8834
  if (applied.has(migration.id))
8825
8835
  continue;
8826
8836
  db.transaction(() => {
@@ -8829,6 +8839,99 @@ function runMigrations(db) {
8829
8839
  })();
8830
8840
  }
8831
8841
  }
8842
+
8843
+ // src/core/assert.ts
8844
+ function assertNever(x, context) {
8845
+ let serialized;
8846
+ try {
8847
+ serialized = JSON.stringify(x);
8848
+ } catch {
8849
+ serialized = String(x);
8850
+ }
8851
+ if (serialized === undefined) {
8852
+ serialized = String(x);
8853
+ }
8854
+ const where = context ? ` (${context})` : "";
8855
+ throw new Error(`Unexpected value reached assertNever${where}: ${serialized}`);
8856
+ }
8857
+
8858
+ // src/core/improve-types.ts
8859
+ function classifyImproveAction(mode) {
8860
+ switch (mode) {
8861
+ case "reflect":
8862
+ case "distill":
8863
+ case "memory-inference":
8864
+ case "graph-extraction":
8865
+ return "accepted";
8866
+ case "reflect-cooldown":
8867
+ case "reflect-skipped":
8868
+ case "distill-skipped":
8869
+ case "reflect-guard-rejected":
8870
+ return "rejected";
8871
+ case "reflect-failed":
8872
+ case "error":
8873
+ return "error";
8874
+ case "memory-prune":
8875
+ return "noop";
8876
+ default:
8877
+ return assertNever(mode);
8878
+ }
8879
+ }
8880
+ var init_improve_types = () => {};
8881
+
8882
+ // src/core/state-db.ts
8883
+ var exports_state_db = {};
8884
+ __export(exports_state_db, {
8885
+ upsertTaskHistory: () => upsertTaskHistory,
8886
+ upsertProposal: () => upsertProposal,
8887
+ upsertExtractedSession: () => upsertExtractedSession,
8888
+ shouldSkipAlreadyExtractedSession: () => shouldSkipAlreadyExtractedSession,
8889
+ runMigrations: () => runMigrations2,
8890
+ recordImproveRun: () => recordImproveRun,
8891
+ readStateEvents: () => readStateEvents,
8892
+ queryTaskHistory: () => queryTaskHistory,
8893
+ queryImproveRuns: () => queryImproveRuns,
8894
+ queryCompletedTaskIntervals: () => queryCompletedTaskIntervals,
8895
+ purgeOldImproveRuns: () => purgeOldImproveRuns,
8896
+ purgeOldEvents: () => purgeOldEvents,
8897
+ proposalToRowValues: () => proposalToRowValues,
8898
+ proposalRowToProposal: () => proposalRowToProposal,
8899
+ openStateDatabase: () => openStateDatabase,
8900
+ listStateProposals: () => listStateProposals,
8901
+ listExistingTableNames: () => listExistingTableNames,
8902
+ insertEvent: () => insertEvent,
8903
+ importEventsJsonl: () => importEventsJsonl,
8904
+ getTaskHistoryRuns: () => getTaskHistoryRuns,
8905
+ getTaskHistory: () => getTaskHistory,
8906
+ getStateProposal: () => getStateProposal,
8907
+ getStateDbPath: () => getStateDbPath,
8908
+ getExtractedSessionsMap: () => getExtractedSessionsMap,
8909
+ getExtractedSession: () => getExtractedSession,
8910
+ eventRowToEnvelope: () => eventRowToEnvelope,
8911
+ computeImproveRunMetrics: () => computeImproveRunMetrics,
8912
+ REGISTRY_INDEX_CACHE_DDL: () => REGISTRY_INDEX_CACHE_DDL
8913
+ });
8914
+ import fs5 from "fs";
8915
+ import path5 from "path";
8916
+ function getStateDbPath() {
8917
+ return path5.join(getDataDir(), "state.db");
8918
+ }
8919
+ function openStateDatabase(dbPath) {
8920
+ const resolvedPath = dbPath ?? getStateDbPath();
8921
+ const dir = path5.dirname(resolvedPath);
8922
+ if (!fs5.existsSync(dir)) {
8923
+ fs5.mkdirSync(dir, { recursive: true });
8924
+ }
8925
+ const db = openDatabase(resolvedPath);
8926
+ db.exec("PRAGMA journal_mode = WAL");
8927
+ db.exec("PRAGMA foreign_keys = ON");
8928
+ db.exec("PRAGMA busy_timeout = 5000");
8929
+ runMigrations2(db);
8930
+ return db;
8931
+ }
8932
+ function runMigrations2(db) {
8933
+ runMigrations(db, MIGRATIONS);
8934
+ }
8832
8935
  function eventRowToEnvelope(row) {
8833
8936
  let metadata;
8834
8937
  try {
@@ -9026,6 +9129,16 @@ function queryTaskHistory(db, options = {}) {
9026
9129
  target_kind, target_ref, metadata_json
9027
9130
  FROM task_history ${where} ORDER BY started_at DESC`).all(...params);
9028
9131
  }
9132
+ function queryCompletedTaskIntervals(db, since, until) {
9133
+ const sql = until ? "SELECT started_at, completed_at FROM task_history WHERE task_id = 'akm-improve' AND started_at >= ? AND started_at < ? AND completed_at IS NOT NULL ORDER BY started_at" : "SELECT started_at, completed_at FROM task_history WHERE task_id = 'akm-improve' AND started_at >= ? AND completed_at IS NOT NULL ORDER BY started_at";
9134
+ return until ? db.prepare(sql).all(since, until) : db.prepare(sql).all(since);
9135
+ }
9136
+ function listExistingTableNames(db, names) {
9137
+ if (names.length === 0)
9138
+ return [];
9139
+ const placeholders = names.map(() => "?").join(", ");
9140
+ return db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (${placeholders}) ORDER BY name`).all(...names);
9141
+ }
9029
9142
  async function importEventsJsonl(db, jsonlPath) {
9030
9143
  const { readFileSync, existsSync } = await import("fs");
9031
9144
  if (!existsSync(jsonlPath)) {
@@ -9082,23 +9195,17 @@ function computeImproveRunMetrics(result) {
9082
9195
  let autoAcceptedCount = 0;
9083
9196
  let errorCount = 0;
9084
9197
  for (const action of actions) {
9085
- switch (action.mode) {
9086
- case "reflect":
9087
- case "distill":
9088
- case "memory-inference":
9089
- case "graph-extraction":
9198
+ switch (classifyImproveAction(action.mode)) {
9199
+ case "accepted":
9090
9200
  acceptedCount++;
9091
9201
  break;
9092
- case "reflect-cooldown":
9093
- case "reflect-skipped":
9094
- case "distill-skipped":
9202
+ case "rejected":
9095
9203
  rejectedCount++;
9096
9204
  break;
9097
- case "reflect-failed":
9098
9205
  case "error":
9099
9206
  errorCount++;
9100
9207
  break;
9101
- case "memory-prune":
9208
+ case "noop":
9102
9209
  break;
9103
9210
  }
9104
9211
  const r = action.result;
@@ -9117,6 +9224,10 @@ function recordImproveRun(db, input) {
9117
9224
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
9118
9225
  `).run(input.id, input.startedAt, input.completedAt, input.stashDir, input.dryRun ? 1 : 0, input.profile, input.scopeMode, input.scopeValue, input.guidance, input.ok ? 1 : 0, JSON.stringify(input.result), JSON.stringify(metricsObj), JSON.stringify(input.metadata ?? {}));
9119
9226
  }
9227
+ function queryImproveRuns(db, since, until) {
9228
+ const sql = until ? "SELECT id, started_at, completed_at, ok, scope_mode, scope_value, result_json FROM improve_runs WHERE started_at >= ? AND started_at < ? AND dry_run = 0 ORDER BY started_at DESC" : "SELECT id, started_at, completed_at, ok, scope_mode, scope_value, result_json FROM improve_runs WHERE started_at >= ? AND dry_run = 0 ORDER BY started_at DESC";
9229
+ return until ? db.prepare(sql).all(since, until) : db.prepare(sql).all(since);
9230
+ }
9120
9231
  function purgeOldImproveRuns(db, retentionDays = 90) {
9121
9232
  if (!Number.isFinite(retentionDays) || retentionDays <= 0)
9122
9233
  return 0;
@@ -9177,6 +9288,8 @@ var MIGRATIONS, REGISTRY_INDEX_CACHE_DDL = `
9177
9288
  ON registry_index_cache(fetched_at);
9178
9289
  `;
9179
9290
  var init_state_db = __esm(() => {
9291
+ init_database();
9292
+ init_improve_types();
9180
9293
  init_paths();
9181
9294
  init_warn();
9182
9295
  MIGRATIONS = [
@@ -9441,6 +9554,21 @@ var init_state_db = __esm(() => {
9441
9554
  ];
9442
9555
  });
9443
9556
 
9557
+ // src/core/best-effort.ts
9558
+ function bestEffort(fn, context) {
9559
+ try {
9560
+ return fn();
9561
+ } catch (err) {
9562
+ if (isVerbose()) {
9563
+ warnVerbose(`[akm:best-effort] ${context ? `${context}: ` : ""}swallowed error`, err);
9564
+ }
9565
+ return;
9566
+ }
9567
+ }
9568
+ var init_best_effort = __esm(() => {
9569
+ init_warn();
9570
+ });
9571
+
9444
9572
  // src/llm/embedders/types.ts
9445
9573
  function cosineSimilarity(a, b) {
9446
9574
  if (a.length !== b.length) {
@@ -9465,7 +9593,98 @@ var init_types = __esm(() => {
9465
9593
  init_warn();
9466
9594
  });
9467
9595
 
9468
- // src/indexer/db-backup.ts
9596
+ // src/runtime.ts
9597
+ import { createHash } from "crypto";
9598
+ import { createRequire as createRequire2 } from "module";
9599
+ function sha256Hex(data) {
9600
+ return createHash("sha256").update(data).digest("hex");
9601
+ }
9602
+ function sleepSync(ms) {
9603
+ if (isBun2) {
9604
+ bunGlobal().sleepSync(ms);
9605
+ return;
9606
+ }
9607
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
9608
+ }
9609
+ function bunGlobal() {
9610
+ return globalThis.Bun;
9611
+ }
9612
+ var isBun2, nodeRequire2, mainPath;
9613
+ var init_runtime = __esm(() => {
9614
+ isBun2 = !!process.versions?.bun;
9615
+ nodeRequire2 = createRequire2(import.meta.url);
9616
+ mainPath = isBun2 ? bunGlobal().main : process.argv[1];
9617
+ });
9618
+
9619
+ // src/indexer/search/search-fields.ts
9620
+ function buildSearchFields(entry) {
9621
+ const name = entry.name.replace(/[-_]/g, " ").toLowerCase();
9622
+ const description = (entry.description ?? "").toLowerCase();
9623
+ const tagParts = [];
9624
+ if (entry.tags)
9625
+ tagParts.push(entry.tags.join(" "));
9626
+ if (entry.aliases)
9627
+ tagParts.push(entry.aliases.join(" "));
9628
+ const tags = tagParts.join(" ").toLowerCase();
9629
+ const hintParts = [];
9630
+ if (entry.searchHints)
9631
+ hintParts.push(entry.searchHints.join(" "));
9632
+ if (entry.examples)
9633
+ hintParts.push(entry.examples.join(" "));
9634
+ if (entry.usage)
9635
+ hintParts.push(entry.usage.join(" "));
9636
+ if (entry.intent) {
9637
+ if (entry.intent.when)
9638
+ hintParts.push(entry.intent.when);
9639
+ if (entry.intent.input)
9640
+ hintParts.push(entry.intent.input);
9641
+ if (entry.intent.output)
9642
+ hintParts.push(entry.intent.output);
9643
+ }
9644
+ if (entry.xrefs)
9645
+ hintParts.push(entry.xrefs.join(" "));
9646
+ if (entry.pageKind)
9647
+ hintParts.push(entry.pageKind);
9648
+ if (entry.whenToUse)
9649
+ hintParts.push(entry.whenToUse);
9650
+ const hints = hintParts.join(" ").toLowerCase();
9651
+ const contentParts = [];
9652
+ if (entry.toc) {
9653
+ contentParts.push(entry.toc.map((h) => h.text).join(" "));
9654
+ }
9655
+ if (entry.parameters) {
9656
+ for (const param of entry.parameters) {
9657
+ contentParts.push(param.name);
9658
+ if (param.description)
9659
+ contentParts.push(param.description);
9660
+ }
9661
+ }
9662
+ const content = contentParts.join(" ").toLowerCase();
9663
+ return { name, description, tags, hints, content };
9664
+ }
9665
+
9666
+ // src/indexer/usage/usage-events.ts
9667
+ function ensureUsageEventsSchema(db) {
9668
+ db.exec(`
9669
+ CREATE TABLE IF NOT EXISTS usage_events (
9670
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
9671
+ event_type TEXT NOT NULL,
9672
+ query TEXT,
9673
+ entry_id INTEGER,
9674
+ entry_ref TEXT,
9675
+ signal TEXT,
9676
+ metadata TEXT,
9677
+ source TEXT NOT NULL DEFAULT 'user',
9678
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
9679
+ );
9680
+ CREATE INDEX IF NOT EXISTS idx_usage_events_entry ON usage_events(entry_id);
9681
+ CREATE INDEX IF NOT EXISTS idx_usage_events_type ON usage_events(event_type);
9682
+ CREATE INDEX IF NOT EXISTS idx_usage_events_ref ON usage_events(entry_ref);
9683
+ CREATE INDEX IF NOT EXISTS idx_usage_events_source ON usage_events(source);
9684
+ `);
9685
+ }
9686
+
9687
+ // src/indexer/db/db-backup.ts
9469
9688
  import fs6 from "fs";
9470
9689
  import path6 from "path";
9471
9690
  function resolveRetention(env = process.env) {
@@ -9507,9 +9726,9 @@ function measureDataDirSize(dirPath) {
9507
9726
  if (entry.isDirectory()) {
9508
9727
  stack.push(full);
9509
9728
  } else if (entry.isFile()) {
9510
- try {
9729
+ bestEffort(() => {
9511
9730
  total += fs6.statSync(full).size;
9512
- } catch {}
9731
+ }, "file vanished between readdir and stat");
9513
9732
  }
9514
9733
  }
9515
9734
  }
@@ -9545,7 +9764,7 @@ function listBackups(dataDir) {
9545
9764
  let sizeBytes;
9546
9765
  let reason = DEFAULT_BACKUP_REASON;
9547
9766
  if (fs6.existsSync(metaPath)) {
9548
- try {
9767
+ bestEffort(() => {
9549
9768
  const raw = fs6.readFileSync(metaPath, "utf8");
9550
9769
  const parsed = JSON.parse(raw);
9551
9770
  if (typeof parsed.createdAt === "string")
@@ -9558,7 +9777,7 @@ function listBackups(dataDir) {
9558
9777
  sizeBytes = parsed.sizeBytes;
9559
9778
  if (typeof parsed.reason === "string" && parsed.reason.length > 0)
9560
9779
  reason = parsed.reason;
9561
- } catch {}
9780
+ }, "malformed backup metadata \u2014 fall back to filesystem-derived values");
9562
9781
  }
9563
9782
  if (!createdAt) {
9564
9783
  try {
@@ -9639,9 +9858,7 @@ function backupDataDir(opts) {
9639
9858
  copyDataDirExcludingBackups(dataDir, finalDest);
9640
9859
  } catch (err) {
9641
9860
  warn("[akm] data dir backup failed \u2014 %s; upgrade will proceed without a snapshot", err instanceof Error ? err.message : String(err));
9642
- try {
9643
- fs6.rmSync(finalDest, { recursive: true, force: true });
9644
- } catch {}
9861
+ bestEffort(() => fs6.rmSync(finalDest, { recursive: true, force: true }), "cleanup partial backup copy");
9645
9862
  return null;
9646
9863
  }
9647
9864
  const createdAt = now.toISOString();
@@ -9697,9 +9914,7 @@ function copyDataDirExcludingBackups(srcRoot, destRoot) {
9697
9914
  fs6.copyFileSync(srcPath, destPath);
9698
9915
  } else if (entry.isSymbolicLink()) {
9699
9916
  const target = fs6.readlinkSync(srcPath);
9700
- try {
9701
- fs6.symlinkSync(target, destPath);
9702
- } catch {}
9917
+ bestEffort(() => fs6.symlinkSync(target, destPath), "symlink creation can fail on Windows without admin");
9703
9918
  }
9704
9919
  }
9705
9920
  }
@@ -9714,77 +9929,10 @@ function tryHostname() {
9714
9929
  }
9715
9930
  var DEFAULT_BACKUP_REASON = "version-upgrade", EMBEDDING_DIM_CHANGE_REASON = "embedding-dim-change", BACKUPS_DIR_NAME = "backups", BACKUP_METADATA_FILE = "backup.meta.json", DEFAULT_RETAIN = 5, FREE_SPACE_MULTIPLIER = 1.1;
9716
9931
  var init_db_backup = __esm(() => {
9932
+ init_best_effort();
9717
9933
  init_warn();
9718
9934
  });
9719
9935
 
9720
- // src/indexer/search-fields.ts
9721
- function buildSearchFields(entry) {
9722
- const name = entry.name.replace(/[-_]/g, " ").toLowerCase();
9723
- const description = (entry.description ?? "").toLowerCase();
9724
- const tagParts = [];
9725
- if (entry.tags)
9726
- tagParts.push(entry.tags.join(" "));
9727
- if (entry.aliases)
9728
- tagParts.push(entry.aliases.join(" "));
9729
- const tags = tagParts.join(" ").toLowerCase();
9730
- const hintParts = [];
9731
- if (entry.searchHints)
9732
- hintParts.push(entry.searchHints.join(" "));
9733
- if (entry.examples)
9734
- hintParts.push(entry.examples.join(" "));
9735
- if (entry.usage)
9736
- hintParts.push(entry.usage.join(" "));
9737
- if (entry.intent) {
9738
- if (entry.intent.when)
9739
- hintParts.push(entry.intent.when);
9740
- if (entry.intent.input)
9741
- hintParts.push(entry.intent.input);
9742
- if (entry.intent.output)
9743
- hintParts.push(entry.intent.output);
9744
- }
9745
- if (entry.xrefs)
9746
- hintParts.push(entry.xrefs.join(" "));
9747
- if (entry.pageKind)
9748
- hintParts.push(entry.pageKind);
9749
- if (entry.whenToUse)
9750
- hintParts.push(entry.whenToUse);
9751
- const hints = hintParts.join(" ").toLowerCase();
9752
- const contentParts = [];
9753
- if (entry.toc) {
9754
- contentParts.push(entry.toc.map((h) => h.text).join(" "));
9755
- }
9756
- if (entry.parameters) {
9757
- for (const param of entry.parameters) {
9758
- contentParts.push(param.name);
9759
- if (param.description)
9760
- contentParts.push(param.description);
9761
- }
9762
- }
9763
- const content = contentParts.join(" ").toLowerCase();
9764
- return { name, description, tags, hints, content };
9765
- }
9766
-
9767
- // src/indexer/usage-events.ts
9768
- function ensureUsageEventsSchema(db) {
9769
- db.exec(`
9770
- CREATE TABLE IF NOT EXISTS usage_events (
9771
- id INTEGER PRIMARY KEY AUTOINCREMENT,
9772
- event_type TEXT NOT NULL,
9773
- query TEXT,
9774
- entry_id INTEGER,
9775
- entry_ref TEXT,
9776
- signal TEXT,
9777
- metadata TEXT,
9778
- source TEXT NOT NULL DEFAULT 'user',
9779
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
9780
- );
9781
- CREATE INDEX IF NOT EXISTS idx_usage_events_entry ON usage_events(entry_id);
9782
- CREATE INDEX IF NOT EXISTS idx_usage_events_type ON usage_events(event_type);
9783
- CREATE INDEX IF NOT EXISTS idx_usage_events_ref ON usage_events(entry_ref);
9784
- CREATE INDEX IF NOT EXISTS idx_usage_events_source ON usage_events(source);
9785
- `);
9786
- }
9787
-
9788
9936
  // src/core/file-lock.ts
9789
9937
  import fs7 from "fs";
9790
9938
  function tryAcquireLockSync(lockPath, payload) {
@@ -9850,7 +9998,7 @@ var init_file_lock = __esm(() => {
9850
9998
  init_common();
9851
9999
  });
9852
10000
 
9853
- // src/core/config-io.ts
10001
+ // src/core/config/config-io.ts
9854
10002
  import fs8 from "fs";
9855
10003
  import path7 from "path";
9856
10004
  function parseConfigText(text, sourcePath) {
@@ -9891,9 +10039,12 @@ function backupExistingConfig(configPath) {
9891
10039
  const backupDir = path7.join(getCacheDir(), "config-backups");
9892
10040
  fs8.mkdirSync(backupDir, { recursive: true });
9893
10041
  const timestamp = new Date().toISOString().replace(/[.:]/g, "-");
9894
- fs8.copyFileSync(configPath, path7.join(backupDir, `config-${timestamp}.json`));
9895
- fs8.copyFileSync(configPath, path7.join(backupDir, "config.latest.json"));
10042
+ const timestamped = path7.join(backupDir, `config-${timestamp}.json`);
10043
+ const latest = path7.join(backupDir, "config.latest.json");
10044
+ fs8.copyFileSync(configPath, timestamped);
10045
+ fs8.copyFileSync(configPath, latest);
9896
10046
  pruneOldBackups2(backupDir);
10047
+ return { timestamped, latest };
9897
10048
  }
9898
10049
  function pruneOldBackups2(backupDir) {
9899
10050
  let entries;
@@ -9919,6 +10070,9 @@ function pruneOldBackups2(backupDir) {
9919
10070
  function getConfigLockPath() {
9920
10071
  return path7.join(getConfigDir(), "config.json.lck");
9921
10072
  }
10073
+ function sleepSyncMs(ms) {
10074
+ sleepSync(ms);
10075
+ }
9922
10076
  function acquireConfigLock() {
9923
10077
  const lockPath = getConfigLockPath();
9924
10078
  try {
@@ -9937,8 +10091,7 @@ function acquireConfigLock() {
9937
10091
  continue;
9938
10092
  }
9939
10093
  if (attempt < CONFIG_LOCK_MAX_RETRIES - 1) {
9940
- const deadline = Date.now() + CONFIG_LOCK_RETRY_DELAY_MS;
9941
- while (Date.now() < deadline) {}
10094
+ sleepSyncMs(CONFIG_LOCK_RETRY_DELAY_MS);
9942
10095
  }
9943
10096
  }
9944
10097
  return () => {};
@@ -9991,17 +10144,801 @@ function stripJsonComments(text) {
9991
10144
  result += text[i];
9992
10145
  i++;
9993
10146
  }
9994
- return result;
10147
+ return result;
10148
+ }
10149
+ var MAX_CONFIG_BACKUPS = 5, CONFIG_LOCK_MAX_RETRIES = 10, CONFIG_LOCK_RETRY_DELAY_MS = 50;
10150
+ var init_config_io = __esm(() => {
10151
+ init_runtime();
10152
+ init_common();
10153
+ init_errors();
10154
+ init_file_lock();
10155
+ init_paths();
10156
+ });
10157
+
10158
+ // src/integrations/harnesses/types.ts
10159
+ class BaseHarness {
10160
+ runtimeId;
10161
+ setupDetectionDir;
10162
+ v1ProfilePrefixes = [];
10163
+ matchesV1ProfileName(name) {
10164
+ if (!this.capabilities.v1Migration)
10165
+ return false;
10166
+ const lower = name.trim().toLowerCase();
10167
+ if (!lower)
10168
+ return false;
10169
+ if (lower === this.id.toLowerCase())
10170
+ return true;
10171
+ for (const alias of this.aliases) {
10172
+ if (lower === alias.toLowerCase())
10173
+ return true;
10174
+ }
10175
+ for (const prefix of this.v1ProfilePrefixes) {
10176
+ if (lower.startsWith(prefix.toLowerCase()))
10177
+ return true;
10178
+ }
10179
+ return false;
10180
+ }
10181
+ }
10182
+
10183
+ // src/integrations/agent/builder-shared.ts
10184
+ var init_builder_shared = __esm(() => {
10185
+ init_errors();
10186
+ });
10187
+
10188
+ // src/integrations/agent/model-aliases.ts
10189
+ var init_model_aliases = () => {};
10190
+
10191
+ // src/integrations/harnesses/claude/agent-builder.ts
10192
+ var init_agent_builder = __esm(() => {
10193
+ init_builder_shared();
10194
+ init_model_aliases();
10195
+ });
10196
+
10197
+ // src/integrations/harnesses/claude/config-import.ts
10198
+ var init_config_import = () => {};
10199
+
10200
+ // src/integrations/session-logs/inline-refs.ts
10201
+ function extractInlineRefMentions(text, ts) {
10202
+ if (!text || text.length < 10)
10203
+ return [];
10204
+ const out = [];
10205
+ REMEMBER_RE.lastIndex = 0;
10206
+ for (const m of text.matchAll(REMEMBER_RE)) {
10207
+ const body = m[1] ?? m[2] ?? "";
10208
+ if (!body.trim())
10209
+ continue;
10210
+ out.push({
10211
+ kind: "remember",
10212
+ text: body,
10213
+ ...ts !== undefined ? { ts } : {}
10214
+ });
10215
+ }
10216
+ FEEDBACK_RE.lastIndex = 0;
10217
+ for (const m of text.matchAll(FEEDBACK_RE)) {
10218
+ const ref = m[1] ?? "";
10219
+ const note = m[2] ?? m[3] ?? "";
10220
+ if (!ref)
10221
+ continue;
10222
+ out.push({
10223
+ kind: "feedback",
10224
+ ref,
10225
+ text: note,
10226
+ ...ts !== undefined ? { ts } : {}
10227
+ });
10228
+ }
10229
+ return out;
10230
+ }
10231
+ var REMEMBER_RE, FEEDBACK_RE;
10232
+ var init_inline_refs = __esm(() => {
10233
+ REMEMBER_RE = /\bakm\s+remember\s+(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')/g;
10234
+ FEEDBACK_RE = /\bakm\s+feedback\s+(\S+)(?:\s+--[a-z-]+)*\s+(?:--note|-n)\s+(?:"((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')/g;
10235
+ });
10236
+
10237
+ // src/integrations/harnesses/claude/session-log.ts
10238
+ import fs9 from "fs";
10239
+ import os from "os";
10240
+ import path8 from "path";
10241
+ function parseClaudeEvent(entry, sessionId, filePath, fallbackTsMs) {
10242
+ if (!entry || typeof entry !== "object")
10243
+ return;
10244
+ const e = entry;
10245
+ const tsRaw = e.timestamp;
10246
+ const ts = typeof tsRaw === "number" ? tsRaw : typeof tsRaw === "string" ? Date.parse(tsRaw) || fallbackTsMs : fallbackTsMs;
10247
+ const message = e.message ?? undefined;
10248
+ const role = typeof message?.role === "string" ? message.role : e.type ?? "unknown";
10249
+ const content = message?.content;
10250
+ let text = "";
10251
+ if (typeof content === "string") {
10252
+ text = content;
10253
+ } else if (Array.isArray(content)) {
10254
+ const parts = [];
10255
+ for (const block of content) {
10256
+ if (!block || typeof block !== "object")
10257
+ continue;
10258
+ const b = block;
10259
+ if (b.type === "text" && typeof b.text === "string")
10260
+ parts.push(b.text);
10261
+ else if (b.type === "thinking" && typeof b.thinking === "string")
10262
+ parts.push(b.thinking);
10263
+ else if (b.type === "tool_use") {
10264
+ const toolName = typeof b.name === "string" ? b.name : "tool";
10265
+ const inputObj = b.input;
10266
+ let inputText = "";
10267
+ if (inputObj && typeof inputObj === "object") {
10268
+ const cmd = inputObj.command;
10269
+ inputText = typeof cmd === "string" ? cmd : JSON.stringify(inputObj);
10270
+ } else if (typeof inputObj === "string") {
10271
+ inputText = inputObj;
10272
+ }
10273
+ parts.push(`[tool:${toolName}] ${inputText}`);
10274
+ } else if (b.type === "tool_result") {
10275
+ const out = typeof b.content === "string" ? b.content : JSON.stringify(b.content ?? "");
10276
+ parts.push(`[tool_result] ${out}`);
10277
+ }
10278
+ }
10279
+ text = parts.join(`
10280
+ `);
10281
+ }
10282
+ if (!text || text.length < 1)
10283
+ return;
10284
+ return {
10285
+ harness: "claude-code",
10286
+ text,
10287
+ ts,
10288
+ sessionId,
10289
+ role,
10290
+ filePath
10291
+ };
10292
+ }
10293
+
10294
+ class ClaudeCodeProvider {
10295
+ name = "claude-code";
10296
+ isAvailable() {
10297
+ return fs9.existsSync(CLAUDE_PROJECTS_DIR);
10298
+ }
10299
+ *readEvents(input) {
10300
+ try {
10301
+ for (const jsonlPath of this.#walkJsonl(CLAUDE_PROJECTS_DIR)) {
10302
+ const stat = fs9.statSync(jsonlPath);
10303
+ if (stat.mtimeMs < input.sinceMs)
10304
+ continue;
10305
+ const lines = fs9.readFileSync(jsonlPath, "utf8").split(`
10306
+ `).filter(Boolean);
10307
+ for (const line of lines) {
10308
+ try {
10309
+ const entry = JSON.parse(line);
10310
+ const text = entry?.message?.content ?? entry?.content ?? "";
10311
+ if (typeof text !== "string" || text.length < 10)
10312
+ continue;
10313
+ yield {
10314
+ harness: this.name,
10315
+ text,
10316
+ ts: typeof entry?.timestamp === "number" ? entry.timestamp : stat.mtimeMs,
10317
+ sessionId: typeof entry?.session_id === "string" ? entry.session_id : undefined,
10318
+ role: typeof entry?.role === "string" ? entry.role : "unknown",
10319
+ filePath: jsonlPath
10320
+ };
10321
+ } catch {}
10322
+ }
10323
+ }
10324
+ } catch {
10325
+ return;
10326
+ }
10327
+ }
10328
+ listSessions(input = {}) {
10329
+ const root = input.location ?? CLAUDE_PROJECTS_DIR;
10330
+ const sinceMs = input.sinceMs ?? 0;
10331
+ const summaries = [];
10332
+ try {
10333
+ for (const jsonlPath of this.#walkJsonl(root)) {
10334
+ let stat;
10335
+ try {
10336
+ stat = fs9.statSync(jsonlPath);
10337
+ } catch {
10338
+ continue;
10339
+ }
10340
+ if (stat.mtimeMs < sinceMs)
10341
+ continue;
10342
+ const sessionId = path8.basename(jsonlPath, ".jsonl");
10343
+ const projectHint = path8.basename(path8.dirname(jsonlPath));
10344
+ const peek = this.#peekJsonl(jsonlPath);
10345
+ summaries.push({
10346
+ harness: this.name,
10347
+ sessionId,
10348
+ filePath: jsonlPath,
10349
+ startedAt: peek.firstTsMs ?? stat.ctimeMs,
10350
+ endedAt: peek.lastTsMs ?? stat.mtimeMs,
10351
+ projectHint,
10352
+ ...peek.title ? { title: peek.title } : {}
10353
+ });
10354
+ }
10355
+ } catch {}
10356
+ return summaries.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0));
10357
+ }
10358
+ readSession(ref) {
10359
+ const stat = fs9.statSync(ref.filePath);
10360
+ const lines = fs9.readFileSync(ref.filePath, "utf8").split(`
10361
+ `).filter(Boolean);
10362
+ const events = [];
10363
+ const inlineRefs = [];
10364
+ let title;
10365
+ let firstTsMs;
10366
+ let lastTsMs;
10367
+ const projectHint = path8.basename(path8.dirname(ref.filePath));
10368
+ for (const line of lines) {
10369
+ let entry;
10370
+ try {
10371
+ entry = JSON.parse(line);
10372
+ } catch {
10373
+ continue;
10374
+ }
10375
+ if (!entry)
10376
+ continue;
10377
+ if (entry.type === "custom-title" && typeof entry.customTitle === "string") {
10378
+ title = entry.customTitle;
10379
+ continue;
10380
+ }
10381
+ const parsed = parseClaudeEvent(entry, ref.sessionId, ref.filePath, stat.mtimeMs);
10382
+ if (!parsed)
10383
+ continue;
10384
+ events.push(parsed);
10385
+ if (firstTsMs === undefined || (parsed.ts ?? 0) < firstTsMs)
10386
+ firstTsMs = parsed.ts;
10387
+ if (lastTsMs === undefined || (parsed.ts ?? 0) > lastTsMs)
10388
+ lastTsMs = parsed.ts;
10389
+ inlineRefs.push(...extractInlineRefMentions(parsed.text, parsed.ts));
10390
+ }
10391
+ return {
10392
+ ref: {
10393
+ harness: this.name,
10394
+ sessionId: ref.sessionId,
10395
+ filePath: ref.filePath,
10396
+ startedAt: firstTsMs ?? stat.ctimeMs,
10397
+ endedAt: lastTsMs ?? stat.mtimeMs,
10398
+ projectHint,
10399
+ ...title ? { title } : {}
10400
+ },
10401
+ events,
10402
+ inlineRefs
10403
+ };
10404
+ }
10405
+ #peekJsonl(filePath) {
10406
+ const result = {};
10407
+ try {
10408
+ const fd = fs9.openSync(filePath, "r");
10409
+ try {
10410
+ const stat = fs9.fstatSync(fd);
10411
+ const headSize = Math.min(stat.size, 4096);
10412
+ const head = Buffer.alloc(headSize);
10413
+ fs9.readSync(fd, head, 0, headSize, 0);
10414
+ const headLines = head.toString("utf8").split(`
10415
+ `).filter(Boolean);
10416
+ for (const line of headLines) {
10417
+ try {
10418
+ const e = JSON.parse(line);
10419
+ if (e.type === "custom-title" && typeof e.customTitle === "string") {
10420
+ result.title = e.customTitle;
10421
+ }
10422
+ if (typeof e.timestamp === "string") {
10423
+ const t = Date.parse(e.timestamp);
10424
+ if (!Number.isNaN(t)) {
10425
+ if (result.firstTsMs === undefined)
10426
+ result.firstTsMs = t;
10427
+ result.lastTsMs = t;
10428
+ }
10429
+ }
10430
+ } catch {}
10431
+ }
10432
+ if (stat.size > 4096) {
10433
+ const tailSize = Math.min(stat.size, 4096);
10434
+ const tail = Buffer.alloc(tailSize);
10435
+ fs9.readSync(fd, tail, 0, tailSize, stat.size - tailSize);
10436
+ const tailLines = tail.toString("utf8").split(`
10437
+ `).filter(Boolean);
10438
+ for (let i = tailLines.length - 1;i >= 0; i--) {
10439
+ try {
10440
+ const e = JSON.parse(tailLines[i] ?? "");
10441
+ if (typeof e.timestamp === "string") {
10442
+ const t = Date.parse(e.timestamp);
10443
+ if (!Number.isNaN(t)) {
10444
+ result.lastTsMs = t;
10445
+ break;
10446
+ }
10447
+ }
10448
+ } catch {}
10449
+ }
10450
+ }
10451
+ } finally {
10452
+ fs9.closeSync(fd);
10453
+ }
10454
+ } catch {}
10455
+ return result;
10456
+ }
10457
+ *#walkJsonl(dir) {
10458
+ try {
10459
+ for (const entry of fs9.readdirSync(dir, { withFileTypes: true })) {
10460
+ const full = path8.join(dir, entry.name);
10461
+ if (entry.isDirectory())
10462
+ yield* this.#walkJsonl(full);
10463
+ else if (entry.name.endsWith(".jsonl"))
10464
+ yield full;
10465
+ }
10466
+ } catch {}
10467
+ }
10468
+ }
10469
+ var CLAUDE_PROJECTS_DIR;
10470
+ var init_session_log = __esm(() => {
10471
+ init_inline_refs();
10472
+ CLAUDE_PROJECTS_DIR = path8.join(os.homedir(), ".claude", "projects");
10473
+ });
10474
+
10475
+ // src/integrations/harnesses/claude/index.ts
10476
+ function caps(c) {
10477
+ return {
10478
+ sessionLogs: false,
10479
+ agentDispatch: false,
10480
+ detection: false,
10481
+ configImport: false,
10482
+ runtimeIdentity: false,
10483
+ v1Migration: false,
10484
+ ...c
10485
+ };
10486
+ }
10487
+ var ClaudeHarness;
10488
+ var init_claude = __esm(() => {
10489
+ init_agent_builder();
10490
+ init_config_import();
10491
+ init_session_log();
10492
+ ClaudeHarness = class ClaudeHarness extends BaseHarness {
10493
+ id = "claude";
10494
+ displayName = "Claude Code";
10495
+ aliases = ["claude-code"];
10496
+ runtimeId = "claude-code";
10497
+ setupDetectionDir = ".claude";
10498
+ capabilities = caps({
10499
+ sessionLogs: true,
10500
+ agentDispatch: true,
10501
+ detection: true,
10502
+ configImport: true,
10503
+ runtimeIdentity: true,
10504
+ v1Migration: true
10505
+ });
10506
+ };
10507
+ });
10508
+
10509
+ // src/integrations/harnesses/opencode/agent-builder.ts
10510
+ var init_agent_builder2 = __esm(() => {
10511
+ init_builder_shared();
10512
+ init_model_aliases();
10513
+ });
10514
+
10515
+ // src/integrations/harnesses/opencode/config-import.ts
10516
+ var init_config_import2 = () => {};
10517
+
10518
+ // src/integrations/harnesses/opencode/session-log.ts
10519
+ import fs10 from "fs";
10520
+ import os2 from "os";
10521
+ import path9 from "path";
10522
+ function getOpenCodeBaseDir() {
10523
+ if (process.platform === "darwin") {
10524
+ return path9.join(os2.homedir(), "Library", "Application Support", "opencode");
10525
+ }
10526
+ return path9.join(os2.homedir(), ".local", "share", "opencode");
10527
+ }
10528
+
10529
+ class OpenCodeProvider {
10530
+ name = "opencode";
10531
+ #baseDir = getOpenCodeBaseDir();
10532
+ isAvailable() {
10533
+ return fs10.existsSync(this.#baseDir);
10534
+ }
10535
+ *readEvents(input) {
10536
+ const candidates = [this.#baseDir, path9.join(this.#baseDir, "log")];
10537
+ for (const dir of candidates) {
10538
+ if (!fs10.existsSync(dir))
10539
+ continue;
10540
+ try {
10541
+ for (const file of fs10.readdirSync(dir)) {
10542
+ const full = path9.join(dir, file);
10543
+ let stat;
10544
+ try {
10545
+ stat = fs10.statSync(full);
10546
+ } catch {
10547
+ continue;
10548
+ }
10549
+ if (!stat.isFile())
10550
+ continue;
10551
+ if (stat.mtimeMs < input.sinceMs)
10552
+ continue;
10553
+ if (!file.endsWith(".json") && !file.endsWith(".jsonl") && !file.endsWith(".log"))
10554
+ continue;
10555
+ const content = fs10.readFileSync(full, "utf8");
10556
+ const lines = content.includes(`
10557
+ `) ? content.split(`
10558
+ `) : [content];
10559
+ for (const line of lines) {
10560
+ try {
10561
+ const entry = JSON.parse(line);
10562
+ const text = entry?.content ?? entry?.message ?? entry?.text ?? "";
10563
+ if (typeof text !== "string" || text.length < 10)
10564
+ continue;
10565
+ yield {
10566
+ harness: this.name,
10567
+ text,
10568
+ ts: typeof entry?.timestamp === "number" ? entry.timestamp : stat.mtimeMs,
10569
+ sessionId: typeof entry?.sessionId === "string" ? entry.sessionId : undefined,
10570
+ role: typeof entry?.role === "string" ? entry.role : "unknown",
10571
+ filePath: full
10572
+ };
10573
+ } catch {}
10574
+ }
10575
+ }
10576
+ } catch {}
10577
+ }
10578
+ }
10579
+ listSessions(input = {}) {
10580
+ const base = input.location ?? this.#baseDir;
10581
+ const sinceMs = input.sinceMs ?? 0;
10582
+ const sessionRoot = path9.join(base, "storage", "session");
10583
+ if (!fs10.existsSync(sessionRoot))
10584
+ return [];
10585
+ const summaries = [];
10586
+ try {
10587
+ for (const projectId of fs10.readdirSync(sessionRoot)) {
10588
+ const projectDir = path9.join(sessionRoot, projectId);
10589
+ let pstat;
10590
+ try {
10591
+ pstat = fs10.statSync(projectDir);
10592
+ } catch {
10593
+ continue;
10594
+ }
10595
+ if (!pstat.isDirectory())
10596
+ continue;
10597
+ for (const file of fs10.readdirSync(projectDir)) {
10598
+ if (!file.endsWith(".json"))
10599
+ continue;
10600
+ const filePath = path9.join(projectDir, file);
10601
+ let stat;
10602
+ try {
10603
+ stat = fs10.statSync(filePath);
10604
+ } catch {
10605
+ continue;
10606
+ }
10607
+ if (stat.mtimeMs < sinceMs)
10608
+ continue;
10609
+ let meta;
10610
+ try {
10611
+ meta = JSON.parse(fs10.readFileSync(filePath, "utf8"));
10612
+ } catch {
10613
+ continue;
10614
+ }
10615
+ const sessionId = typeof meta?.id === "string" ? meta.id : path9.basename(file, ".json");
10616
+ const time = meta?.time ?? undefined;
10617
+ const startedAt = typeof time?.created === "number" ? time.created : stat.ctimeMs;
10618
+ const endedAt = typeof time?.updated === "number" ? time.updated : stat.mtimeMs;
10619
+ const title = typeof meta?.title === "string" ? meta.title : undefined;
10620
+ const projectHint = typeof meta?.directory === "string" ? meta.directory : projectId;
10621
+ summaries.push({
10622
+ harness: this.name,
10623
+ sessionId,
10624
+ filePath,
10625
+ startedAt,
10626
+ endedAt,
10627
+ projectHint,
10628
+ ...title ? { title } : {}
10629
+ });
10630
+ }
10631
+ }
10632
+ } catch {}
10633
+ return summaries.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0));
10634
+ }
10635
+ readSession(ref) {
10636
+ let meta = {};
10637
+ try {
10638
+ meta = JSON.parse(fs10.readFileSync(ref.filePath, "utf8"));
10639
+ } catch {}
10640
+ const time = meta.time ?? undefined;
10641
+ const startedAt = typeof time?.created === "number" ? time.created : undefined;
10642
+ const endedAt = typeof time?.updated === "number" ? time.updated : undefined;
10643
+ const title = typeof meta.title === "string" ? meta.title : undefined;
10644
+ const projectHint = typeof meta.directory === "string" ? meta.directory : undefined;
10645
+ const events = [];
10646
+ const inlineRefs = [];
10647
+ const inferredBase = this.#inferBaseFromSessionPath(ref.filePath) ?? this.#baseDir;
10648
+ const msgDir = path9.join(inferredBase, "storage", "message", ref.sessionId);
10649
+ if (fs10.existsSync(msgDir)) {
10650
+ try {
10651
+ const files = fs10.readdirSync(msgDir).filter((f) => f.endsWith(".json"));
10652
+ for (const file of files) {
10653
+ const full = path9.join(msgDir, file);
10654
+ let msg;
10655
+ try {
10656
+ msg = JSON.parse(fs10.readFileSync(full, "utf8"));
10657
+ } catch {
10658
+ continue;
10659
+ }
10660
+ if (!msg)
10661
+ continue;
10662
+ const evt = this.#messageToEvent(msg, ref.sessionId, full);
10663
+ if (evt) {
10664
+ events.push(evt);
10665
+ inlineRefs.push(...extractInlineRefMentions(evt.text, evt.ts));
10666
+ }
10667
+ }
10668
+ } catch {}
10669
+ }
10670
+ events.sort((a, b) => (a.ts ?? 0) - (b.ts ?? 0));
10671
+ return {
10672
+ ref: {
10673
+ harness: this.name,
10674
+ sessionId: ref.sessionId,
10675
+ filePath: ref.filePath,
10676
+ ...startedAt !== undefined ? { startedAt } : {},
10677
+ ...endedAt !== undefined ? { endedAt } : {},
10678
+ ...projectHint ? { projectHint } : {},
10679
+ ...title ? { title } : {}
10680
+ },
10681
+ events,
10682
+ inlineRefs
10683
+ };
10684
+ }
10685
+ #inferBaseFromSessionPath(filePath) {
10686
+ const dir = path9.dirname(filePath);
10687
+ const parts = dir.split(path9.sep);
10688
+ if (parts.length < 3)
10689
+ return;
10690
+ const last = parts[parts.length - 1];
10691
+ const sndLast = parts[parts.length - 2];
10692
+ const thirdLast = parts[parts.length - 3];
10693
+ if (sndLast !== "session" || thirdLast !== "storage" || !last)
10694
+ return;
10695
+ return parts.slice(0, parts.length - 3).join(path9.sep);
10696
+ }
10697
+ #messageToEvent(msg, sessionId, filePath) {
10698
+ const time = msg.time ?? undefined;
10699
+ const ts = typeof time?.created === "number" ? time.created : typeof msg.timestamp === "number" ? msg.timestamp : 0;
10700
+ const role = typeof msg.role === "string" ? msg.role : "unknown";
10701
+ const summary = msg.summary;
10702
+ const parts = [];
10703
+ if (typeof summary?.title === "string")
10704
+ parts.push(summary.title);
10705
+ if (Array.isArray(summary?.parts)) {
10706
+ for (const p of summary.parts) {
10707
+ if (typeof p === "string")
10708
+ parts.push(p);
10709
+ else if (p && typeof p === "object") {
10710
+ const text2 = p.text;
10711
+ if (typeof text2 === "string")
10712
+ parts.push(text2);
10713
+ }
10714
+ }
10715
+ }
10716
+ if (typeof msg.content === "string")
10717
+ parts.push(msg.content);
10718
+ const text = parts.join(`
10719
+ `).trim();
10720
+ if (text.length < 1)
10721
+ return;
10722
+ return {
10723
+ harness: this.name,
10724
+ text,
10725
+ ts: ts || undefined,
10726
+ sessionId,
10727
+ role,
10728
+ filePath
10729
+ };
10730
+ }
10731
+ }
10732
+ var init_session_log2 = __esm(() => {
10733
+ init_inline_refs();
10734
+ });
10735
+
10736
+ // src/integrations/harnesses/opencode/index.ts
10737
+ function caps2(c) {
10738
+ return {
10739
+ sessionLogs: false,
10740
+ agentDispatch: false,
10741
+ detection: false,
10742
+ configImport: false,
10743
+ runtimeIdentity: false,
10744
+ v1Migration: false,
10745
+ ...c
10746
+ };
10747
+ }
10748
+ var OpencodeHarness;
10749
+ var init_opencode = __esm(() => {
10750
+ init_agent_builder2();
10751
+ init_config_import2();
10752
+ init_session_log2();
10753
+ OpencodeHarness = class OpencodeHarness extends BaseHarness {
10754
+ id = "opencode";
10755
+ displayName = "OpenCode";
10756
+ aliases = [];
10757
+ setupDetectionDir = ".config/opencode";
10758
+ v1ProfilePrefixes = ["opencode"];
10759
+ capabilities = caps2({
10760
+ sessionLogs: true,
10761
+ agentDispatch: true,
10762
+ detection: true,
10763
+ configImport: true,
10764
+ runtimeIdentity: true,
10765
+ v1Migration: true
10766
+ });
10767
+ };
10768
+ });
10769
+
10770
+ // src/integrations/agent/profiles.ts
10771
+ var COMMON_PASSTHROUGH, BUILTINS, HEADLESS_BUILTINS, BUILTIN_AGENT_PROFILE_NAMES;
10772
+ var init_profiles = __esm(() => {
10773
+ COMMON_PASSTHROUGH = ["HOME", "PATH", "USER", "LANG", "LC_ALL", "TERM", "TMPDIR"];
10774
+ BUILTINS = {
10775
+ opencode: {
10776
+ name: "opencode",
10777
+ bin: "opencode",
10778
+ args: ["run"],
10779
+ stdio: "interactive",
10780
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENCODE_API_KEY", "OPENCODE_CONFIG"],
10781
+ parseOutput: "text"
10782
+ },
10783
+ claude: {
10784
+ name: "claude",
10785
+ bin: "claude",
10786
+ args: [],
10787
+ stdio: "interactive",
10788
+ envPassthrough: [...COMMON_PASSTHROUGH, "ANTHROPIC_API_KEY", "CLAUDE_CONFIG"],
10789
+ parseOutput: "text"
10790
+ },
10791
+ codex: {
10792
+ name: "codex",
10793
+ bin: "codex",
10794
+ args: [],
10795
+ stdio: "interactive",
10796
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "CODEX_CONFIG"],
10797
+ parseOutput: "text"
10798
+ },
10799
+ gemini: {
10800
+ name: "gemini",
10801
+ bin: "gemini",
10802
+ args: [],
10803
+ stdio: "interactive",
10804
+ envPassthrough: [...COMMON_PASSTHROUGH, "GEMINI_API_KEY", "GOOGLE_API_KEY"],
10805
+ parseOutput: "text"
10806
+ },
10807
+ aider: {
10808
+ name: "aider",
10809
+ bin: "aider",
10810
+ args: ["--no-auto-commits"],
10811
+ stdio: "interactive",
10812
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
10813
+ parseOutput: "text"
10814
+ }
10815
+ };
10816
+ HEADLESS_BUILTINS = {
10817
+ "opencode-headless": {
10818
+ name: "opencode-headless",
10819
+ bin: "opencode",
10820
+ args: ["run"],
10821
+ stdio: "captured",
10822
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENCODE_API_KEY", "OPENCODE_CONFIG"],
10823
+ parseOutput: "json"
10824
+ },
10825
+ "claude-headless": {
10826
+ name: "claude-headless",
10827
+ bin: "claude",
10828
+ args: [],
10829
+ stdio: "captured",
10830
+ envPassthrough: [...COMMON_PASSTHROUGH, "ANTHROPIC_API_KEY", "CLAUDE_CONFIG"],
10831
+ parseOutput: "json"
10832
+ },
10833
+ "codex-headless": {
10834
+ name: "codex-headless",
10835
+ bin: "codex",
10836
+ args: [],
10837
+ stdio: "captured",
10838
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "CODEX_CONFIG"],
10839
+ parseOutput: "json"
10840
+ },
10841
+ "gemini-headless": {
10842
+ name: "gemini-headless",
10843
+ bin: "gemini",
10844
+ args: [],
10845
+ stdio: "captured",
10846
+ envPassthrough: [...COMMON_PASSTHROUGH, "GEMINI_API_KEY", "GOOGLE_API_KEY"],
10847
+ parseOutput: "json"
10848
+ },
10849
+ "aider-headless": {
10850
+ name: "aider-headless",
10851
+ bin: "aider",
10852
+ args: ["--no-auto-commits"],
10853
+ stdio: "captured",
10854
+ envPassthrough: [...COMMON_PASSTHROUGH, "OPENAI_API_KEY", "ANTHROPIC_API_KEY"],
10855
+ parseOutput: "json"
10856
+ }
10857
+ };
10858
+ BUILTIN_AGENT_PROFILE_NAMES = Object.freeze(Object.keys(BUILTINS).sort());
10859
+ });
10860
+
10861
+ // src/integrations/agent/config.ts
10862
+ var init_config = __esm(() => {
10863
+ init_config2();
10864
+ init_errors();
10865
+ init_warn();
10866
+ init_profiles();
10867
+ });
10868
+
10869
+ // src/integrations/harnesses/opencode-sdk/sdk-runner.ts
10870
+ var init_sdk_runner = __esm(() => {
10871
+ init_config2();
10872
+ init_config();
10873
+ });
10874
+
10875
+ // src/integrations/harnesses/opencode-sdk/index.ts
10876
+ function caps3(c) {
10877
+ return {
10878
+ sessionLogs: false,
10879
+ agentDispatch: false,
10880
+ detection: false,
10881
+ configImport: false,
10882
+ runtimeIdentity: false,
10883
+ v1Migration: false,
10884
+ ...c
10885
+ };
10886
+ }
10887
+ var OpencodeSdkHarness;
10888
+ var init_opencode_sdk = __esm(() => {
10889
+ init_sdk_runner();
10890
+ OpencodeSdkHarness = class OpencodeSdkHarness extends BaseHarness {
10891
+ id = "opencode-sdk";
10892
+ displayName = "OpenCode SDK";
10893
+ aliases = [];
10894
+ v1ProfilePrefixes = ["opencode-sdk"];
10895
+ capabilities = caps3({
10896
+ agentDispatch: true,
10897
+ detection: true,
10898
+ v1Migration: true
10899
+ });
10900
+ };
10901
+ });
10902
+
10903
+ // src/integrations/harnesses/index.ts
10904
+ function v1ProfilePlatform(name) {
10905
+ for (const h of V1_RESOLUTION_ORDER) {
10906
+ if (h.matchesV1ProfileName(name))
10907
+ return h.id;
10908
+ }
10909
+ return;
9995
10910
  }
9996
- var MAX_CONFIG_BACKUPS = 5, CONFIG_LOCK_MAX_RETRIES = 10, CONFIG_LOCK_RETRY_DELAY_MS = 50;
9997
- var init_config_io = __esm(() => {
9998
- init_common();
9999
- init_errors();
10000
- init_file_lock();
10001
- init_paths();
10911
+ var HARNESS_REGISTRY, HARNESS_BY_ID, HARNESS_BY_ANY_ID, VALID_HARNESS_IDS, SESSION_LOG_HARNESSES, AGENT_DISPATCH_HARNESSES, CONFIG_IMPORTER_HARNESSES, DETECTION_HARNESSES, V1_RESOLUTION_ORDER;
10912
+ var init_harnesses = __esm(() => {
10913
+ init_claude();
10914
+ init_opencode();
10915
+ init_opencode_sdk();
10916
+ HARNESS_REGISTRY = Object.freeze([
10917
+ new OpencodeHarness,
10918
+ new ClaudeHarness,
10919
+ new OpencodeSdkHarness
10920
+ ]);
10921
+ HARNESS_BY_ID = new Map(HARNESS_REGISTRY.map((h) => [h.id, h]));
10922
+ HARNESS_BY_ANY_ID = (() => {
10923
+ const m = new Map;
10924
+ for (const h of HARNESS_REGISTRY) {
10925
+ m.set(h.id, h);
10926
+ if (h.runtimeId)
10927
+ m.set(h.runtimeId, h);
10928
+ for (const a of h.aliases)
10929
+ m.set(a, h);
10930
+ }
10931
+ return m;
10932
+ })();
10933
+ VALID_HARNESS_IDS = Object.freeze(HARNESS_REGISTRY.map((h) => h.id));
10934
+ SESSION_LOG_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.sessionLogs);
10935
+ AGENT_DISPATCH_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.agentDispatch);
10936
+ CONFIG_IMPORTER_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.configImport);
10937
+ DETECTION_HARNESSES = HARNESS_REGISTRY.filter((h) => h.capabilities.detection);
10938
+ V1_RESOLUTION_ORDER = [...HARNESS_REGISTRY].sort((a, b) => b.id.length - a.id.length);
10002
10939
  });
10003
10940
 
10004
- // src/core/config-migration.ts
10941
+ // src/core/config/config-migration.ts
10005
10942
  function compareConfigVersion(a, b) {
10006
10943
  const partsA = normalizeVersion(a);
10007
10944
  const partsB = normalizeVersion(b);
@@ -10450,14 +11387,7 @@ function migrateConfigShape(raw) {
10450
11387
  return { changed, result };
10451
11388
  }
10452
11389
  function guessAgentPlatform(name) {
10453
- const lower = name.toLowerCase();
10454
- if (lower === "claude" || lower === "claude-code")
10455
- return "claude";
10456
- if (lower.startsWith("opencode-sdk"))
10457
- return "opencode-sdk";
10458
- if (lower.startsWith("opencode"))
10459
- return "opencode";
10460
- return;
11390
+ return v1ProfilePlatform(name);
10461
11391
  }
10462
11392
  function mapV1ProcessName(name) {
10463
11393
  switch (name) {
@@ -10486,6 +11416,7 @@ function mapV1ProcessName(name) {
10486
11416
  }
10487
11417
  var CURRENT_CONFIG_VERSION = "0.8.0";
10488
11418
  var init_config_migration = __esm(() => {
11419
+ init_harnesses();
10489
11420
  init_warn();
10490
11421
  });
10491
11422
 
@@ -10536,10 +11467,10 @@ var init_util = __esm(() => {
10536
11467
  util2.assertEqual = (_) => {};
10537
11468
  function assertIs(_arg) {}
10538
11469
  util2.assertIs = assertIs;
10539
- function assertNever(_x) {
11470
+ function assertNever2(_x) {
10540
11471
  throw new Error;
10541
11472
  }
10542
- util2.assertNever = assertNever;
11473
+ util2.assertNever = assertNever2;
10543
11474
  util2.arrayToEnum = (items) => {
10544
11475
  const obj = {};
10545
11476
  for (const item of items) {
@@ -10933,8 +11864,8 @@ class ParseStatus {
10933
11864
  }
10934
11865
  }
10935
11866
  var makeIssue = (params) => {
10936
- const { data, path: path8, errorMaps, issueData } = params;
10937
- const fullPath = [...path8, ...issueData.path || []];
11867
+ const { data, path: path10, errorMaps, issueData } = params;
11868
+ const fullPath = [...path10, ...issueData.path || []];
10938
11869
  const fullIssue = {
10939
11870
  ...issueData,
10940
11871
  path: fullPath
@@ -10980,11 +11911,11 @@ var init_errorUtil = __esm(() => {
10980
11911
 
10981
11912
  // node_modules/zod/v3/types.js
10982
11913
  class ParseInputLazyPath {
10983
- constructor(parent, value, path8, key) {
11914
+ constructor(parent, value, path10, key) {
10984
11915
  this._cachedPath = [];
10985
11916
  this.parent = parent;
10986
11917
  this.data = value;
10987
- this._path = path8;
11918
+ this._path = path10;
10988
11919
  this._key = key;
10989
11920
  }
10990
11921
  get path() {
@@ -14455,10 +15386,16 @@ var init_zod = __esm(() => {
14455
15386
  init_external();
14456
15387
  });
14457
15388
 
14458
- // src/core/config-schema.ts
14459
- var positiveInt, nonNegativeNumber, nonEmptyString, httpUrl, LlmCapabilitiesSchema, LlmConnectionConfigSchema, LlmProfileConfigSchema, EmbeddingOllamaOptionsSchema, EmbeddingConnectionConfigSchema, AgentPlatformSchema, AgentProfileConfigSchema, ImproveProcessConfigSchema, ImproveProfileProcessesSchema, ImproveProfileConfigSchema, ProfilesSchema, DefaultsSchema, SourceConfigEntryOptionsSchema, SourceConfigEntrySchema, RegistryConfigEntrySchema, KitSourceSchema, InstalledStashEntrySchema, OutputConfigSchema, SearchGraphBoostSchema, SearchConfigSchema, FeedbackConfigSchema, ImproveUtilityDecaySchema, ImproveConfigSchema, GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED, INDEX_PASS_PROVIDER_KEYS, INDEX_PASS_KNOWN_KEYS, IndexPassConfigSchema, MetadataEnhanceSchema, StalenessDetectionSchema, IndexConfigSchema, AkmConfigShape, AkmConfigBaseSchema, AkmConfigSchema;
15389
+ // src/core/config/config-types.ts
15390
+ var init_config_types = __esm(() => {
15391
+ init_harnesses();
15392
+ });
15393
+
15394
+ // src/core/config/config-schema.ts
15395
+ var positiveInt, nonNegativeNumber, nonEmptyString, httpUrl, LlmCapabilitiesSchema, LlmConnectionConfigSchema, LlmProfileConfigSchema, EmbeddingOllamaOptionsSchema, EmbeddingConnectionConfigSchema, AgentPlatformSchema, AgentProfileConfigSchema, ImproveProcessConfigSchema, ImproveProfileProcessesSchema, ImproveProfileConfigSchema, ProfilesSchema, DefaultsSchema, SourceConfigEntryOptionsSchema, SourceConfigEntrySchema, RegistryConfigEntrySchema, KitSourceSchema, InstalledStashEntrySchema, OutputConfigSchema, SearchGraphBoostSchema, SearchConfigSchema, FeedbackConfigSchema, ImproveUtilityDecaySchema, ImproveConfigSchema, GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED, INDEX_PASS_PROVIDER_KEYS, INDEX_PASS_KNOWN_KEYS, IndexPassConfigSchema, MetadataEnhanceSchema, StalenessDetectionSchema, IndexConfigSchema, SetupTaskSchedulesSchema, SetupConfigSchema, AkmConfigShape, AkmConfigBaseSchema, AkmConfigSchema;
14460
15396
  var init_config_schema = __esm(() => {
14461
15397
  init_zod();
15398
+ init_config_types();
14462
15399
  positiveInt = exports_external.number().int().positive();
14463
15400
  nonNegativeNumber = exports_external.number().finite().min(0);
14464
15401
  nonEmptyString = exports_external.string().min(1).refine((v) => v.trim().length > 0, { message: "expected a non-empty string" });
@@ -14502,7 +15439,7 @@ var init_config_schema = __esm(() => {
14502
15439
  contextLength: positiveInt.optional(),
14503
15440
  ollamaOptions: EmbeddingOllamaOptionsSchema.optional()
14504
15441
  }).strict();
14505
- AgentPlatformSchema = exports_external.enum(["opencode", "claude", "opencode-sdk"]);
15442
+ AgentPlatformSchema = exports_external.enum(VALID_HARNESS_IDS);
14506
15443
  AgentProfileConfigSchema = exports_external.object({
14507
15444
  platform: AgentPlatformSchema,
14508
15445
  bin: exports_external.string().min(1).optional(),
@@ -14516,11 +15453,15 @@ var init_config_schema = __esm(() => {
14516
15453
  profile: exports_external.string().min(1).optional(),
14517
15454
  timeoutMs: exports_external.union([positiveInt, exports_external.null()]).optional(),
14518
15455
  allowedTypes: exports_external.array(exports_external.string().min(1)).optional(),
15456
+ minPoolSize: exports_external.number().int().min(0).optional(),
14519
15457
  qualityGate: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
14520
15458
  contradictionDetection: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
14521
15459
  defaultSince: exports_external.string().min(1).optional(),
14522
15460
  maxTotalChars: positiveInt.optional(),
14523
15461
  maxChunkSize: exports_external.number().int().min(1).max(50).optional(),
15462
+ minNewSessions: exports_external.number().int().min(0).optional(),
15463
+ indexSessions: exports_external.boolean().optional(),
15464
+ minSessionDuration: exports_external.number().min(0).optional(),
14524
15465
  applyMode: exports_external.enum(["queue", "promote"]).optional(),
14525
15466
  policy: exports_external.string().min(1).optional(),
14526
15467
  maxAcceptsPerRun: positiveInt.optional(),
@@ -14778,6 +15719,13 @@ var init_config_schema = __esm(() => {
14778
15719
  metadataEnhance: MetadataEnhanceSchema.optional(),
14779
15720
  stalenessDetection: StalenessDetectionSchema.optional()
14780
15721
  }).catchall(IndexPassConfigSchema));
15722
+ SetupTaskSchedulesSchema = exports_external.object({
15723
+ improve: exports_external.string().min(1).optional(),
15724
+ index: exports_external.string().min(1).optional()
15725
+ }).strict();
15726
+ SetupConfigSchema = exports_external.object({
15727
+ taskSchedules: SetupTaskSchedulesSchema.optional()
15728
+ }).strict();
14781
15729
  AkmConfigShape = {
14782
15730
  configVersion: exports_external.union([exports_external.string().min(1), exports_external.number()]).optional(),
14783
15731
  profiles: ProfilesSchema.optional(),
@@ -14795,7 +15743,8 @@ var init_config_schema = __esm(() => {
14795
15743
  search: SearchConfigSchema.optional(),
14796
15744
  feedback: FeedbackConfigSchema.optional(),
14797
15745
  archiveRetentionDays: nonNegativeNumber.optional(),
14798
- improve: ImproveConfigSchema.optional()
15746
+ improve: ImproveConfigSchema.optional(),
15747
+ setup: SetupConfigSchema.optional()
14799
15748
  };
14800
15749
  AkmConfigBaseSchema = exports_external.object(AkmConfigShape).strict();
14801
15750
  AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
@@ -14818,8 +15767,8 @@ var init_config_schema = __esm(() => {
14818
15767
  });
14819
15768
  });
14820
15769
 
14821
- // src/core/config-sources.ts
14822
- import { createHash } from "crypto";
15770
+ // src/core/config/config-sources.ts
15771
+ import { createHash as createHash2 } from "crypto";
14823
15772
  function deriveStashEntryName(entry) {
14824
15773
  if (entry.name)
14825
15774
  return entry.name;
@@ -14828,7 +15777,7 @@ function deriveStashEntryName(entry) {
14828
15777
  path: entry.path ?? null,
14829
15778
  url: entry.url ?? null
14830
15779
  });
14831
- const hash = createHash("sha256").update(seed).digest("hex").slice(0, 8);
15780
+ const hash = createHash2("sha256").update(seed).digest("hex").slice(0, 8);
14832
15781
  return `${entry.type}-${hash}`;
14833
15782
  }
14834
15783
  function parseSourceSpec(entry) {
@@ -14897,7 +15846,7 @@ function toConfiguredSource(persisted, isPrimary) {
14897
15846
  }
14898
15847
  var init_config_sources = () => {};
14899
15848
 
14900
- // src/core/config.ts
15849
+ // src/core/config/config.ts
14901
15850
  var exports_config = {};
14902
15851
  __export(exports_config, {
14903
15852
  updateConfig: () => updateConfig,
@@ -14915,12 +15864,13 @@ __export(exports_config, {
14915
15864
  getIndexPassConfig: () => getIndexPassConfig,
14916
15865
  getEffectiveRegistries: () => getEffectiveRegistries,
14917
15866
  getDefaultLlmConfig: () => getDefaultLlmConfig,
15867
+ VALID_HARNESS_IDS: () => VALID_HARNESS_IDS,
14918
15868
  FEEDBACK_FAILURE_MODES: () => FEEDBACK_FAILURE_MODES,
14919
15869
  DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE: () => DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE,
14920
15870
  DEFAULT_CONFIG: () => DEFAULT_CONFIG
14921
15871
  });
14922
- import fs9 from "fs";
14923
- import path8 from "path";
15872
+ import fs11 from "fs";
15873
+ import path10 from "path";
14924
15874
  function resolveBatchSize(configured, contextLength) {
14925
15875
  const base = configured && configured > 0 ? configured : DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE;
14926
15876
  if (!contextLength || contextLength <= 0)
@@ -14935,7 +15885,7 @@ function loadUserConfig() {
14935
15885
  const configPath = getConfigPath();
14936
15886
  let stat;
14937
15887
  try {
14938
- stat = fs9.statSync(configPath);
15888
+ stat = fs11.statSync(configPath);
14939
15889
  } catch {
14940
15890
  cachedConfig = undefined;
14941
15891
  return applyRuntimeEnvApiKeys({ ...DEFAULT_CONFIG });
@@ -14945,7 +15895,7 @@ function loadUserConfig() {
14945
15895
  }
14946
15896
  let text;
14947
15897
  try {
14948
- text = fs9.readFileSync(configPath, "utf8");
15898
+ text = fs11.readFileSync(configPath, "utf8");
14949
15899
  } catch {
14950
15900
  cachedConfig = undefined;
14951
15901
  return applyRuntimeEnvApiKeys({ ...DEFAULT_CONFIG });
@@ -14954,7 +15904,7 @@ function loadUserConfig() {
14954
15904
  const finalConfig = applyRuntimeEnvApiKeys(parseAndValidate(text, configPath));
14955
15905
  let finalStat = stat;
14956
15906
  try {
14957
- finalStat = fs9.statSync(configPath);
15907
+ finalStat = fs11.statSync(configPath);
14958
15908
  } catch {}
14959
15909
  cachedConfig = {
14960
15910
  config: finalConfig,
@@ -15057,8 +16007,8 @@ function loadConfig() {
15057
16007
  function saveConfig(config) {
15058
16008
  cachedConfig = undefined;
15059
16009
  const configPath = getConfigPath();
15060
- const dir = path8.dirname(configPath);
15061
- fs9.mkdirSync(dir, { recursive: true });
16010
+ const dir = path10.dirname(configPath);
16011
+ fs11.mkdirSync(dir, { recursive: true });
15062
16012
  const sanitized = sanitizeConfigForWrite(config);
15063
16013
  const parseResult = AkmConfigSchema.safeParse(sanitized);
15064
16014
  if (!parseResult.success) {
@@ -15203,14 +16153,14 @@ function applyRuntimeEnvApiKeys(config) {
15203
16153
  return next;
15204
16154
  }
15205
16155
  function warnIfProjectConfigPresent(startDir) {
15206
- let currentDir = path8.resolve(startDir);
16156
+ let currentDir = path10.resolve(startDir);
15207
16157
  while (true) {
15208
- const configPath = path8.join(currentDir, PROJECT_CONFIG_RELATIVE_PATH);
16158
+ const configPath = path10.join(currentDir, PROJECT_CONFIG_RELATIVE_PATH);
15209
16159
  if (isFile(configPath) && !PROJECT_CONFIG_DEPRECATION_WARNED.has(configPath)) {
15210
16160
  PROJECT_CONFIG_DEPRECATION_WARNED.add(configPath);
15211
16161
  warn(`[akm] DEPRECATED: project-level config file found at ${configPath}. ` + "Project-level config files are no longer merged (removed after 0.8.x deprecation). " + "Move any needed settings to ~/.config/akm/config.json; this file is ignored.");
15212
16162
  }
15213
- const parentDir = path8.dirname(currentDir);
16163
+ const parentDir = path10.dirname(currentDir);
15214
16164
  if (parentDir === currentDir)
15215
16165
  break;
15216
16166
  currentDir = parentDir;
@@ -15218,20 +16168,21 @@ function warnIfProjectConfigPresent(startDir) {
15218
16168
  }
15219
16169
  function isFile(filePath) {
15220
16170
  try {
15221
- return fs9.statSync(filePath).isFile();
16171
+ return fs11.statSync(filePath).isFile();
15222
16172
  } catch {
15223
16173
  return false;
15224
16174
  }
15225
16175
  }
15226
16176
  var FEEDBACK_FAILURE_MODES, DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE = 4, GRAPH_EXTRACTION_CHARS_PER_BODY = 1500, DEFAULT_CONFIG, PROJECT_CONFIG_RELATIVE_PATH, cachedConfig, INDEX_RESERVED_KEYS, PROJECT_CONFIG_DEPRECATION_WARNED;
15227
- var init_config = __esm(() => {
16177
+ var init_config2 = __esm(() => {
16178
+ init_errors();
15228
16179
  init_config_io();
15229
16180
  init_config_migration();
15230
16181
  init_config_schema();
15231
- init_errors();
15232
16182
  init_config_io();
15233
16183
  init_paths();
15234
16184
  init_warn();
16185
+ init_config_types();
15235
16186
  init_config_sources();
15236
16187
  FEEDBACK_FAILURE_MODES = [
15237
16188
  "incorrect",
@@ -15251,12 +16202,12 @@ var init_config = __esm(() => {
15251
16202
  detail: "brief"
15252
16203
  }
15253
16204
  };
15254
- PROJECT_CONFIG_RELATIVE_PATH = path8.join(".akm", "config.json");
16205
+ PROJECT_CONFIG_RELATIVE_PATH = path10.join(".akm", "config.json");
15255
16206
  INDEX_RESERVED_KEYS = new Set(["metadataEnhance", "stalenessDetection"]);
15256
16207
  PROJECT_CONFIG_DEPRECATION_WARNED = new Set;
15257
16208
  });
15258
16209
 
15259
- // src/indexer/db.ts
16210
+ // src/indexer/db/db.ts
15260
16211
  var exports_db = {};
15261
16212
  __export(exports_db, {
15262
16213
  warnIfVecMissing: () => warnIfVecMissing,
@@ -15274,7 +16225,7 @@ __export(exports_db, {
15274
16225
  relinkUsageEvents: () => relinkUsageEvents,
15275
16226
  rebuildFts: () => rebuildFts,
15276
16227
  openExistingDatabase: () => openExistingDatabase,
15277
- openDatabase: () => openDatabase,
16228
+ openDatabase: () => openDatabase2,
15278
16229
  isVecAvailable: () => isVecAvailable,
15279
16230
  getZeroResultSearches: () => getZeroResultSearches,
15280
16231
  getUtilityScoresByIds: () => getUtilityScoresByIds,
@@ -15287,11 +16238,15 @@ __export(exports_db, {
15287
16238
  getLlmCacheEntry: () => getLlmCacheEntry,
15288
16239
  getLlmCacheEntriesByRefs: () => getLlmCacheEntriesByRefs,
15289
16240
  getIndexDirState: () => getIndexDirState,
16241
+ getEntryRefRowsForStashRoot: () => getEntryRefRowsForStashRoot,
16242
+ getEntryIdByFilePath: () => getEntryIdByFilePath,
16243
+ getEntryFilePathById: () => getEntryFilePathById,
15290
16244
  getEntryCount: () => getEntryCount,
15291
16245
  getEntryByRef: () => getEntryByRef,
15292
16246
  getEntryById: () => getEntryById,
15293
16247
  getEntriesByDir: () => getEntriesByDir,
15294
16248
  getEmbeddingCount: () => getEmbeddingCount,
16249
+ getEmbeddableEntryCount: () => getEmbeddableEntryCount,
15295
16250
  getDerivedForParent: () => getDerivedForParent,
15296
16251
  getAllEntriesForEmbedding: () => getAllEntriesForEmbedding,
15297
16252
  getAllEntries: () => getAllEntries,
@@ -15303,6 +16258,7 @@ __export(exports_db, {
15303
16258
  deleteEntriesByDir: () => deleteEntriesByDir,
15304
16259
  computeSourceHash: () => computeSourceHash,
15305
16260
  computeBodyHash: () => computeBodyHash,
16261
+ collectTagSetFromEntries: () => collectTagSetFromEntries,
15306
16262
  closeDatabase: () => closeDatabase,
15307
16263
  clearStaleCacheEntries: () => clearStaleCacheEntries,
15308
16264
  bumpUtilityScoresBatch: () => bumpUtilityScoresBatch,
@@ -15313,17 +16269,16 @@ __export(exports_db, {
15313
16269
  EMBEDDING_DIM: () => EMBEDDING_DIM,
15314
16270
  DB_VERSION: () => DB_VERSION
15315
16271
  });
15316
- import { Database as Database2 } from "bun:sqlite";
15317
- import fs10 from "fs";
15318
- import { createRequire } from "module";
15319
- import path9 from "path";
15320
- function openDatabase(dbPath, options) {
16272
+ import fs12 from "fs";
16273
+ import { createRequire as createRequire3 } from "module";
16274
+ import path11 from "path";
16275
+ function openDatabase2(dbPath, options) {
15321
16276
  const resolvedPath = dbPath ?? getDbPath();
15322
- const dir = path9.dirname(resolvedPath);
15323
- if (!fs10.existsSync(dir)) {
15324
- fs10.mkdirSync(dir, { recursive: true });
16277
+ const dir = path11.dirname(resolvedPath);
16278
+ if (!fs12.existsSync(dir)) {
16279
+ fs12.mkdirSync(dir, { recursive: true });
15325
16280
  }
15326
- const db = new Database2(resolvedPath);
16281
+ const db = openDatabase(resolvedPath);
15327
16282
  db.exec("PRAGMA journal_mode = WAL");
15328
16283
  db.exec("PRAGMA busy_timeout = 5000");
15329
16284
  db.exec("PRAGMA foreign_keys = ON");
@@ -15335,7 +16290,7 @@ function openDatabase(dbPath, options) {
15335
16290
  }
15336
16291
  function resolveConfiguredEmbeddingDim() {
15337
16292
  try {
15338
- const { loadConfig: loadConfig2 } = (init_config(), __toCommonJS(exports_config));
16293
+ const { loadConfig: loadConfig2 } = (init_config2(), __toCommonJS(exports_config));
15339
16294
  const dim = loadConfig2().embedding?.dimension;
15340
16295
  if (typeof dim === "number" && Number.isInteger(dim) && dim > 0 && dim <= 4096) {
15341
16296
  return dim;
@@ -15347,7 +16302,7 @@ function resolveConfiguredEmbeddingDim() {
15347
16302
  }
15348
16303
  function openExistingDatabase(dbPath) {
15349
16304
  const resolvedPath = dbPath ?? getDbPath();
15350
- const db = new Database2(resolvedPath);
16305
+ const db = openDatabase(resolvedPath);
15351
16306
  db.exec("PRAGMA journal_mode = WAL");
15352
16307
  db.exec("PRAGMA busy_timeout = 5000");
15353
16308
  db.exec("PRAGMA foreign_keys = ON");
@@ -15359,7 +16314,7 @@ function closeDatabase(db) {
15359
16314
  }
15360
16315
  function loadVecExtension(db) {
15361
16316
  try {
15362
- const esmRequire = createRequire(import.meta.url);
16317
+ const esmRequire = createRequire3(import.meta.url);
15363
16318
  const sqliteVec = esmRequire("sqlite-vec");
15364
16319
  sqliteVec.load(db);
15365
16320
  vecStatus.set(db, true);
@@ -15375,7 +16330,7 @@ function warnIfVecMissing(db, { once } = { once: false }) {
15375
16330
  return;
15376
16331
  if (once && vecInitWarnedDbs.has(db))
15377
16332
  return;
15378
- try {
16333
+ bestEffort(() => {
15379
16334
  const row = db.prepare("SELECT COUNT(*) AS cnt FROM embeddings").get();
15380
16335
  const count = row?.cnt ?? 0;
15381
16336
  if (count >= VEC_FALLBACK_THRESHOLD) {
@@ -15384,7 +16339,7 @@ function warnIfVecMissing(db, { once } = { once: false }) {
15384
16339
  if (once)
15385
16340
  vecInitWarnedDbs.add(db);
15386
16341
  }
15387
- } catch {}
16342
+ }, "embeddings table may not exist yet during init");
15388
16343
  }
15389
16344
  function ensureSchema(db, embeddingDim, options) {
15390
16345
  db.exec(`
@@ -15590,12 +16545,8 @@ function ensureSchema(db, embeddingDim, options) {
15590
16545
  const storedDim = getMeta(db, "embeddingDim");
15591
16546
  if (storedDim && storedDim !== String(embeddingDim)) {
15592
16547
  backupBeforeEmbeddingDimChange(options?.dataDir, storedDim, String(embeddingDim));
15593
- try {
15594
- db.exec("DROP TABLE IF EXISTS entries_vec");
15595
- } catch {}
15596
- try {
15597
- db.exec("DELETE FROM embeddings");
15598
- } catch {}
16548
+ bestEffort(() => db.exec("DROP TABLE IF EXISTS entries_vec"), "drop entries_vec on dim change");
16549
+ bestEffort(() => db.exec("DELETE FROM embeddings"), "delete stale embeddings on dim change");
15599
16550
  setMeta(db, "hasEmbeddings", "0");
15600
16551
  }
15601
16552
  }
@@ -15619,9 +16570,7 @@ function ensureSchema(db, embeddingDim, options) {
15619
16570
  const storedDim = getMeta(db, "embeddingDim");
15620
16571
  if (storedDim && storedDim !== String(embeddingDim)) {
15621
16572
  backupBeforeEmbeddingDimChange(options?.dataDir, storedDim, String(embeddingDim));
15622
- try {
15623
- db.exec("DELETE FROM embeddings");
15624
- } catch {}
16573
+ bestEffort(() => db.exec("DELETE FROM embeddings"), "delete embeddings on explicit dim change");
15625
16574
  setMeta(db, "hasEmbeddings", "0");
15626
16575
  }
15627
16576
  setMeta(db, "embeddingDim", String(embeddingDim));
@@ -15636,9 +16585,9 @@ function handleVersionUpgrade(db) {
15636
16585
  if (storedVersion === undefined || storedVersion === "" || storedVersion === String(DB_VERSION))
15637
16586
  return [];
15638
16587
  let usageBackup = [];
15639
- try {
16588
+ bestEffort(() => {
15640
16589
  usageBackup = db.prepare("SELECT * FROM usage_events").all();
15641
- } catch {}
16590
+ }, "usage_events table may not exist in older versions");
15642
16591
  db.exec("DROP TABLE IF EXISTS utility_scores");
15643
16592
  db.exec("DROP TABLE IF EXISTS utility_scores_scoped");
15644
16593
  db.exec("DROP INDEX IF EXISTS idx_utility_scores_scoped_entry_id");
@@ -15755,7 +16704,7 @@ function deleteIndexDirState(db, dirPath) {
15755
16704
  db.prepare("DELETE FROM index_dir_state WHERE dir_path = ?").run(dirPath);
15756
16705
  }
15757
16706
  function deleteIndexDirStatesByStashDir(db, stashDir) {
15758
- db.prepare("DELETE FROM index_dir_state WHERE dir_path = ? OR dir_path LIKE ?").run(stashDir, `${stashDir}${path9.sep}%`);
16707
+ db.prepare("DELETE FROM index_dir_state WHERE dir_path = ? OR dir_path LIKE ?").run(stashDir, `${stashDir}${path11.sep}%`);
15759
16708
  }
15760
16709
  function upsertEntry(db, entryKey, dirPath, filePath, stashDir, entry, searchText) {
15761
16710
  const stmts = getUpsertStmts(db);
@@ -15790,14 +16739,14 @@ function getUpsertStmts(db) {
15790
16739
  return stmts;
15791
16740
  }
15792
16741
  function ensureDerivedFromColumn(db) {
15793
- try {
16742
+ bestEffort(() => {
15794
16743
  const cols = db.prepare("PRAGMA table_info(entries)").all();
15795
16744
  const hasColumn = cols.some((c) => c.name === "derived_from");
15796
16745
  if (!hasColumn) {
15797
16746
  db.exec("ALTER TABLE entries ADD COLUMN derived_from TEXT");
15798
16747
  }
15799
16748
  db.exec("CREATE INDEX IF NOT EXISTS idx_entries_derived_from ON entries(derived_from)");
15800
- } catch {}
16749
+ }, "entries table may not exist on a brand-new DB before CREATE \u2014 caller is responsible");
15801
16750
  }
15802
16751
  function getDerivedForParent(db, parentRef) {
15803
16752
  if (!parentRef)
@@ -15837,7 +16786,7 @@ function getPositiveFeedbackCountsByIds(db, ids) {
15837
16786
  for (let i = 0;i < ids.length; i += SQLITE_CHUNK_SIZE) {
15838
16787
  const chunk = ids.slice(i, i + SQLITE_CHUNK_SIZE);
15839
16788
  const placeholders = chunk.map(() => "?").join(",");
15840
- try {
16789
+ bestEffort(() => {
15841
16790
  const rows = db.prepare(`SELECT entry_id, COUNT(*) AS cnt
15842
16791
  FROM usage_events
15843
16792
  WHERE event_type = 'feedback'
@@ -15849,7 +16798,7 @@ function getPositiveFeedbackCountsByIds(db, ids) {
15849
16798
  result.set(row.entry_id, row.cnt);
15850
16799
  }
15851
16800
  }
15852
- } catch {}
16801
+ }, "usage_events table may be missing on legacy DBs \u2014 treat as zero counts");
15853
16802
  }
15854
16803
  return result;
15855
16804
  }
@@ -15874,33 +16823,19 @@ function deleteRelatedRows(db, ids) {
15874
16823
  for (let i = 0;i < numericIds.length; i += SQLITE_CHUNK_SIZE) {
15875
16824
  const chunk = numericIds.slice(i, i + SQLITE_CHUNK_SIZE);
15876
16825
  const placeholders = chunk.map(() => "?").join(",");
15877
- try {
15878
- db.prepare(`DELETE FROM entries_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
15879
- } catch {}
15880
- try {
15881
- db.prepare(`DELETE FROM entries_fts_dirty WHERE entry_id IN (${placeholders})`).run(...chunk);
15882
- } catch {}
16826
+ bestEffort(() => db.prepare(`DELETE FROM entries_fts WHERE entry_id IN (${placeholders})`).run(...chunk), "fts table may not exist on a brand-new db");
16827
+ bestEffort(() => db.prepare(`DELETE FROM entries_fts_dirty WHERE entry_id IN (${placeholders})`).run(...chunk), "fts dirty table is created lazily by upsertEntry");
15883
16828
  }
15884
16829
  for (let i = 0;i < numericIds.length; i += SQLITE_CHUNK_SIZE) {
15885
16830
  const chunk = numericIds.slice(i, i + SQLITE_CHUNK_SIZE);
15886
16831
  const placeholders = chunk.map(() => "?").join(",");
15887
- try {
15888
- db.prepare(`DELETE FROM embeddings WHERE id IN (${placeholders})`).run(...chunk);
15889
- } catch {}
16832
+ bestEffort(() => db.prepare(`DELETE FROM embeddings WHERE id IN (${placeholders})`).run(...chunk), "delete embeddings for entries");
15890
16833
  if (vecAvail) {
15891
- try {
15892
- db.prepare(`DELETE FROM entries_vec WHERE id IN (${placeholders})`).run(...chunk);
15893
- } catch {}
16834
+ bestEffort(() => db.prepare(`DELETE FROM entries_vec WHERE id IN (${placeholders})`).run(...chunk), "delete entries_vec for entries");
15894
16835
  }
15895
- try {
15896
- db.prepare(`DELETE FROM utility_scores WHERE entry_id IN (${placeholders})`).run(...chunk);
15897
- } catch {}
15898
- try {
15899
- db.prepare(`DELETE FROM utility_scores_scoped WHERE entry_id IN (${placeholders})`).run(...chunk);
15900
- } catch {}
15901
- try {
15902
- db.prepare(`DELETE FROM usage_events WHERE entry_id IN (${placeholders})`).run(...chunk);
15903
- } catch {}
16836
+ bestEffort(() => db.prepare(`DELETE FROM utility_scores WHERE entry_id IN (${placeholders})`).run(...chunk), "delete utility_scores for entries");
16837
+ bestEffort(() => db.prepare(`DELETE FROM utility_scores_scoped WHERE entry_id IN (${placeholders})`).run(...chunk), "delete utility_scores_scoped for entries");
16838
+ bestEffort(() => db.prepare(`DELETE FROM usage_events WHERE entry_id IN (${placeholders})`).run(...chunk), "delete usage_events for entries");
15904
16839
  }
15905
16840
  }
15906
16841
  function deleteEntriesByIds(db, ids) {
@@ -15963,12 +16898,12 @@ function upsertEmbedding(db, entryId, embedding) {
15963
16898
  const buf = float32Buffer(embedding);
15964
16899
  db.prepare("INSERT OR REPLACE INTO embeddings (id, embedding) VALUES (?, ?)").run(entryId, buf);
15965
16900
  if (isVecAvailable(db)) {
15966
- try {
16901
+ bestEffort(() => {
15967
16902
  db.transaction(() => {
15968
16903
  db.prepare("DELETE FROM entries_vec WHERE id = ?").run(entryId);
15969
16904
  db.prepare("INSERT INTO entries_vec (id, embedding) VALUES (?, ?)").run(entryId, buf);
15970
16905
  })();
15971
- } catch {}
16906
+ }, "vec table unavailable or constraint failure");
15972
16907
  }
15973
16908
  return true;
15974
16909
  }
@@ -16172,6 +17107,10 @@ function getEntryCount(db) {
16172
17107
  const row = db.prepare("SELECT COUNT(*) AS cnt FROM entries").get();
16173
17108
  return row.cnt;
16174
17109
  }
17110
+ function getEmbeddableEntryCount(db) {
17111
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM entries").get();
17112
+ return row.cnt;
17113
+ }
16175
17114
  function getEmbeddingCount(db) {
16176
17115
  const row = db.prepare("SELECT COUNT(*) AS cnt FROM embeddings").get();
16177
17116
  return row.cnt;
@@ -16193,6 +17132,17 @@ function getEntriesByDir(db, dirPath) {
16193
17132
  const rows = db.prepare("SELECT id, entry_key, dir_path, file_path, stash_dir, entry_json, search_text FROM entries WHERE dir_path = ?").all(dirPath);
16194
17133
  return parseEntryRows(rows, "getEntriesByDir");
16195
17134
  }
17135
+ function getEntryIdByFilePath(db, filePath) {
17136
+ const row = db.prepare("SELECT id FROM entries WHERE file_path = ? LIMIT 1").get(filePath);
17137
+ return row?.id;
17138
+ }
17139
+ function getEntryFilePathById(db, id) {
17140
+ const row = db.prepare("SELECT file_path FROM entries WHERE id = ?").get(id);
17141
+ return row?.file_path;
17142
+ }
17143
+ function getEntryRefRowsForStashRoot(db, stashRoot) {
17144
+ return db.prepare("SELECT file_path, entry_json FROM entries WHERE stash_dir = ? OR file_path LIKE ?").all(stashRoot, `${stashRoot}%`);
17145
+ }
16196
17146
  function getUtilityScore(db, entryId) {
16197
17147
  const row = db.prepare("SELECT entry_id, utility, show_count, search_count, select_rate, last_used_at, updated_at FROM utility_scores WHERE entry_id = ?").get(entryId);
16198
17148
  if (!row)
@@ -16302,18 +17252,16 @@ function upsertLlmCacheEntry(db, assetRef, bodyHash, resultJson, cacheVariant =
16302
17252
  updated_at = excluded.updated_at`).run(assetRef, cacheVariant, bodyHash, resultJson, Date.now());
16303
17253
  }
16304
17254
  function clearStaleCacheEntries(db) {
16305
- try {
17255
+ bestEffort(() => {
16306
17256
  db.exec(`
16307
17257
  DELETE FROM llm_enrichment_cache
16308
17258
  WHERE asset_ref NOT IN (SELECT file_path FROM entries)
16309
17259
  AND asset_ref NOT IN (SELECT entry_key FROM entries)
16310
17260
  `);
16311
- } catch {}
17261
+ }, "llm_enrichment_cache may not exist in very old DBs opened without ensureSchema");
16312
17262
  }
16313
17263
  function computeBodyHash(body) {
16314
- const hasher = new Bun.CryptoHasher("sha256");
16315
- hasher.update(body);
16316
- return hasher.digest("hex");
17264
+ return sha256Hex(body);
16317
17265
  }
16318
17266
  function getRetrievalCounts(db, refs) {
16319
17267
  if (refs.length === 0)
@@ -16368,7 +17316,6 @@ function getAllEntriesForEmbedding(db) {
16368
17316
  return db.prepare(`
16369
17317
  SELECT e.id, e.search_text AS searchText, e.entry_key AS entryKey, e.file_path AS filePath FROM entries e
16370
17318
  WHERE NOT EXISTS (SELECT 1 FROM embeddings b WHERE b.id = e.id)
16371
- AND e.entry_type != 'vault'
16372
17319
  `).all();
16373
17320
  }
16374
17321
  function upsertWorkflowDocument(db, entryId, doc, content) {
@@ -16432,7 +17379,7 @@ function applyFeedbackToUtilityScore(db, entryId, positiveCount, negativeCount)
16432
17379
  return { previousUtility, nextUtility, crossedReviewThreshold };
16433
17380
  }
16434
17381
  function relinkUsageEvents(db) {
16435
- try {
17382
+ bestEffort(() => {
16436
17383
  db.exec(`
16437
17384
  UPDATE usage_events
16438
17385
  SET entry_id = NULL
@@ -16447,7 +17394,7 @@ function relinkUsageEvents(db) {
16447
17394
  )
16448
17395
  WHERE entry_id IS NULL AND entry_ref IS NOT NULL
16449
17396
  `);
16450
- } catch {}
17397
+ }, "usage_events table may not exist yet during entry_id re-resolution");
16451
17398
  }
16452
17399
  function upsertRegistryIndexCache(db, registryUrl, indexJson, opts) {
16453
17400
  db.prepare(`
@@ -16470,20 +17417,44 @@ function getRegistryIndexCache(db, registryUrl, maxAgeMs = 3600000) {
16470
17417
  return;
16471
17418
  return { indexJson: row.index_json, etag: row.etag, lastModified: row.last_modified };
16472
17419
  }
17420
+ function collectTagSetFromEntries(db, entryType) {
17421
+ const tags = new Set;
17422
+ const stmt = entryType ? db.prepare("SELECT entry_json FROM entries WHERE entry_type = ?") : db.prepare("SELECT entry_json FROM entries");
17423
+ const rows = entryType ? stmt.all(entryType) : stmt.all();
17424
+ for (const row of rows) {
17425
+ let parsed;
17426
+ try {
17427
+ parsed = JSON.parse(row.entry_json);
17428
+ } catch {
17429
+ continue;
17430
+ }
17431
+ if (!Array.isArray(parsed.tags))
17432
+ continue;
17433
+ for (const tag of parsed.tags) {
17434
+ if (typeof tag === "string" && tag.trim().length > 0) {
17435
+ tags.add(tag.trim().toLowerCase());
17436
+ }
17437
+ }
17438
+ }
17439
+ return tags;
17440
+ }
16473
17441
  var DB_VERSION = 17, EMBEDDING_DIM = 384, GRAPH_SCHEMA_VERSION = 3, vecStatus, VEC_DOCS_URL = "https://github.com/itlackey/akm/blob/main/docs/configuration.md#sqlite-vec-extension", VEC_FALLBACK_THRESHOLD = 1e4, vecInitWarnedDbs, SQLITE_CHUNK_SIZE = 500, upsertStmtsByDb, FEEDBACK_LR = 0.1, FEEDBACK_REWARD_POSITIVE = 1, FEEDBACK_REWARD_NEGATIVE = 0, MAX_NEG_DELTA_PER_CALL = 0.15, UTILITY_REVIEW_THRESHOLD = 0.5, HIGH_UTILITY_THRESHOLD = 0.5;
16474
17442
  var init_db = __esm(() => {
16475
17443
  init_asset_ref();
17444
+ init_best_effort();
16476
17445
  init_paths();
16477
17446
  init_state_db();
16478
17447
  init_warn();
16479
17448
  init_types();
17449
+ init_runtime();
17450
+ init_database();
16480
17451
  init_db_backup();
16481
17452
  vecStatus = new WeakMap;
16482
17453
  vecInitWarnedDbs = new WeakSet;
16483
17454
  upsertStmtsByDb = new WeakMap;
16484
17455
  });
16485
17456
 
16486
- // src/indexer/graph-db.ts
17457
+ // src/indexer/db/graph-db.ts
16487
17458
  var exports_graph_db = {};
16488
17459
  __export(exports_graph_db, {
16489
17460
  resolveEntryIdForPath: () => resolveEntryIdForPath,
@@ -16495,12 +17466,12 @@ __export(exports_graph_db, {
16495
17466
  loadGraphEntitiesByEntry: () => loadGraphEntitiesByEntry,
16496
17467
  deleteStoredGraph: () => deleteStoredGraph
16497
17468
  });
16498
- import fs11 from "fs";
17469
+ import fs13 from "fs";
16499
17470
  function withReadableGraphDb(db, fn) {
16500
17471
  if (db)
16501
17472
  return fn(db);
16502
17473
  const dbPath = getDbPath();
16503
- if (!fs11.existsSync(dbPath))
17474
+ if (!fs13.existsSync(dbPath))
16504
17475
  throw new Error("GRAPH_DB_MISSING");
16505
17476
  const opened = openExistingDatabase(dbPath);
16506
17477
  try {
@@ -16720,7 +17691,8 @@ function loadStoredGraphMeta(stashPath, db) {
16720
17691
  cacheHits: row.cache_hits,
16721
17692
  cacheMisses: row.cache_misses,
16722
17693
  truncationCount: row.truncation_count,
16723
- failureCount: row.failure_count
17694
+ failureCount: row.failure_count,
17695
+ retryAttempts: 0
16724
17696
  }
16725
17697
  };
16726
17698
  } catch {
@@ -16820,10 +17792,17 @@ var init_graph_db = __esm(() => {
16820
17792
 
16821
17793
  // scripts/migrate-storage.ts
16822
17794
  init_paths();
16823
- import fs12 from "fs";
16824
- import os from "os";
16825
- import path10 from "path";
17795
+ import fs14 from "fs";
17796
+ import os3 from "os";
17797
+ import path12 from "path";
16826
17798
  import readline from "readline";
17799
+
17800
+ // src/indexer/usage/unmigrated-vaults-guard.ts
17801
+ init_warn();
17802
+ var MIGRATED_MARKER = ".migrated";
17803
+ var warnedStashDirs = new Set;
17804
+
17805
+ // scripts/migrate-storage.ts
16827
17806
  var args = process.argv.slice(2);
16828
17807
  var DRY_RUN = args.includes("--dry-run");
16829
17808
  var YES = args.includes("--yes");
@@ -16840,12 +17819,12 @@ function parseFromArg() {
16840
17819
  return val;
16841
17820
  }
16842
17821
  var FROM_VERSION = parseFromArg();
16843
- var dataDir = process.env.AKM_DATA_DIR?.trim() ?? (process.env.XDG_DATA_HOME?.trim() ? path10.join(process.env.XDG_DATA_HOME.trim(), "akm") : path10.join(os.homedir(), ".local", "share", "akm"));
16844
- var stateDir = process.env.AKM_STATE_DIR?.trim() ?? (process.env.XDG_STATE_HOME?.trim() ? path10.join(process.env.XDG_STATE_HOME.trim(), "akm") : path10.join(os.homedir(), ".local", "state", "akm"));
17822
+ var dataDir = process.env.AKM_DATA_DIR?.trim() ?? (process.env.XDG_DATA_HOME?.trim() ? path12.join(process.env.XDG_DATA_HOME.trim(), "akm") : path12.join(os3.homedir(), ".local", "share", "akm"));
17823
+ var stateDir = process.env.AKM_STATE_DIR?.trim() ?? (process.env.XDG_STATE_HOME?.trim() ? path12.join(process.env.XDG_STATE_HOME.trim(), "akm") : path12.join(os3.homedir(), ".local", "state", "akm"));
16845
17824
  var cacheDir = getCacheDir();
16846
17825
  var configDir = getConfigDir();
16847
- var stateDbPath = path10.join(dataDir, "state.db");
16848
- var indexDbPath = path10.join(dataDir, "index.db");
17826
+ var stateDbPath = path12.join(dataDir, "state.db");
17827
+ var indexDbPath = path12.join(dataDir, "index.db");
16849
17828
  var PATHS = {
16850
17829
  cacheDir,
16851
17830
  configDir,
@@ -16856,92 +17835,97 @@ var PATHS = {
16856
17835
  };
16857
17836
  var versionReports = [];
16858
17837
  function ensureDir(dir) {
16859
- if (!fs12.existsSync(dir)) {
16860
- fs12.mkdirSync(dir, { recursive: true });
17838
+ if (!fs14.existsSync(dir)) {
17839
+ fs14.mkdirSync(dir, { recursive: true });
16861
17840
  }
16862
17841
  }
16863
17842
  function copyAndVerify(src, dest) {
16864
- fs12.copyFileSync(src, dest);
16865
- const srcStat = fs12.statSync(src);
16866
- const destStat = fs12.statSync(dest);
17843
+ fs14.copyFileSync(src, dest);
17844
+ const srcStat = fs14.statSync(src);
17845
+ const destStat = fs14.statSync(dest);
16867
17846
  return destStat.size === srcStat.size;
16868
17847
  }
16869
- function copyDirRecursive(src, dest) {
17848
+ function copyTree(src, dest, opts) {
16870
17849
  let copied = 0;
17850
+ let skipped = 0;
16871
17851
  let failed = 0;
16872
17852
  ensureDir(dest);
16873
- for (const entry of fs12.readdirSync(src, { withFileTypes: true })) {
16874
- const srcEntry = path10.join(src, entry.name);
16875
- const destEntry = path10.join(dest, entry.name);
17853
+ for (const entry of fs14.readdirSync(src, { withFileTypes: true })) {
17854
+ const srcEntry = path12.join(src, entry.name);
17855
+ const destEntry = path12.join(dest, entry.name);
16876
17856
  if (entry.isDirectory()) {
16877
- const sub = copyDirRecursive(srcEntry, destEntry);
17857
+ const sub = copyTree(srcEntry, destEntry, opts);
16878
17858
  copied += sub.copied;
17859
+ skipped += sub.skipped;
16879
17860
  failed += sub.failed;
16880
- } else {
16881
- try {
16882
- if (copyAndVerify(srcEntry, destEntry)) {
16883
- copied++;
16884
- } else {
16885
- failed++;
16886
- }
16887
- } catch {
17861
+ continue;
17862
+ }
17863
+ if (!opts.clobber && fs14.existsSync(destEntry)) {
17864
+ skipped++;
17865
+ continue;
17866
+ }
17867
+ try {
17868
+ if (copyAndVerify(srcEntry, destEntry)) {
17869
+ copied++;
17870
+ } else {
16888
17871
  failed++;
16889
17872
  }
17873
+ } catch {
17874
+ failed++;
16890
17875
  }
16891
17876
  }
16892
- return { copied, failed };
17877
+ return { copied, skipped, failed };
16893
17878
  }
16894
17879
  function countFilesRecursive(dir) {
16895
17880
  let count = 0;
16896
- for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
17881
+ for (const entry of fs14.readdirSync(dir, { withFileTypes: true })) {
16897
17882
  if (entry.isDirectory()) {
16898
- count += countFilesRecursive(path10.join(dir, entry.name));
17883
+ count += countFilesRecursive(path12.join(dir, entry.name));
16899
17884
  } else {
16900
17885
  count++;
16901
17886
  }
16902
17887
  }
16903
17888
  return count;
16904
17889
  }
17890
+ async function runSteps(steps, ctx) {
17891
+ for (const step of steps) {
17892
+ ctx.recordStep(await step.run(ctx));
17893
+ }
17894
+ }
16905
17895
  function migrateDb(ctx, filename) {
16906
- const src = path10.join(ctx.paths.cacheDir, filename);
16907
- const dest = path10.join(ctx.paths.dataDir, filename);
16908
- if (!fs12.existsSync(src)) {
16909
- ctx.recordStep({ name: filename, status: "skipped", detail: "source not found" });
16910
- return;
17896
+ const src = path12.join(ctx.paths.cacheDir, filename);
17897
+ const dest = path12.join(ctx.paths.dataDir, filename);
17898
+ if (!fs14.existsSync(src)) {
17899
+ return { name: filename, status: "skipped", detail: "source not found" };
16911
17900
  }
16912
- if (fs12.existsSync(dest)) {
16913
- ctx.recordStep({ name: filename, status: "skipped", detail: "destination already exists" });
16914
- return;
17901
+ if (fs14.existsSync(dest)) {
17902
+ return { name: filename, status: "skipped", detail: "destination already exists" };
16915
17903
  }
16916
17904
  if (ctx.dryRun) {
16917
- ctx.recordStep({ name: filename, status: "success", detail: `[dry-run] would copy ${src} \u2192 ${dest}` });
16918
- return;
17905
+ return { name: filename, status: "success", detail: `[dry-run] would copy ${src} \u2192 ${dest}` };
16919
17906
  }
16920
17907
  ensureDir(ctx.paths.dataDir);
16921
17908
  const ok = copyAndVerify(src, dest);
16922
17909
  if (ok) {
16923
- ctx.recordStep({
17910
+ return {
16924
17911
  name: filename,
16925
17912
  status: "success",
16926
17913
  detail: `copied to ${dest} \u2014 source left at ${src} (delete manually when ready)`
16927
- });
16928
- } else {
16929
- ctx.recordStep({ name: filename, status: "failed", detail: `size mismatch after copy: ${src} \u2192 ${dest}` });
17914
+ };
16930
17915
  }
17916
+ return { name: filename, status: "failed", detail: `size mismatch after copy: ${src} \u2192 ${dest}` };
16931
17917
  }
16932
17918
  async function migrateEventsJsonl(ctx) {
16933
- const src = path10.join(ctx.paths.cacheDir, "events.jsonl");
16934
- if (!fs12.existsSync(src)) {
16935
- ctx.recordStep({ name: "events.jsonl \u2192 state.db", status: "skipped", detail: "source not found" });
16936
- return;
17919
+ const src = path12.join(ctx.paths.cacheDir, "events.jsonl");
17920
+ if (!fs14.existsSync(src)) {
17921
+ return { name: "events.jsonl \u2192 state.db", status: "skipped", detail: "source not found" };
16937
17922
  }
16938
17923
  if (ctx.dryRun) {
16939
- ctx.recordStep({
17924
+ return {
16940
17925
  name: "events.jsonl \u2192 state.db",
16941
17926
  status: "success",
16942
17927
  detail: `[dry-run] would import ${src} into ${ctx.paths.stateDbPath}`
16943
- });
16944
- return;
17928
+ };
16945
17929
  }
16946
17930
  try {
16947
17931
  ensureDir(ctx.paths.dataDir);
@@ -16963,46 +17947,43 @@ async function migrateEventsJsonl(ctx) {
16963
17947
  throw err;
16964
17948
  }
16965
17949
  const dedupNote = skipped > 0 ? ` (${skipped} duplicate(s) skipped \u2014 re-run idempotency)` : "";
16966
- ctx.recordStep({
17950
+ return {
16967
17951
  name: "events.jsonl \u2192 state.db",
16968
17952
  status: "success",
16969
17953
  detail: `imported ${imported} events (max id: ${maxId})${dedupNote} \u2014 source left at ${src} (delete manually when ready)`
16970
- });
17954
+ };
16971
17955
  } finally {
16972
17956
  db.close();
16973
17957
  }
16974
17958
  } catch (err) {
16975
17959
  const msg = err instanceof Error ? err.message : String(err);
16976
- ctx.recordStep({ name: "events.jsonl \u2192 state.db", status: "failed", detail: msg });
17960
+ return { name: "events.jsonl \u2192 state.db", status: "failed", detail: msg };
16977
17961
  }
16978
17962
  }
16979
17963
  function migrateTaskHistory(ctx) {
16980
- const src = path10.join(ctx.paths.cacheDir, "tasks", "history");
16981
- const dest = path10.join(ctx.paths.stateDir, "tasks", "history");
16982
- if (!fs12.existsSync(src)) {
16983
- ctx.recordStep({ name: "tasks/history/", status: "skipped", detail: "source directory not found" });
16984
- return;
17964
+ const src = path12.join(ctx.paths.cacheDir, "tasks", "history");
17965
+ const dest = path12.join(ctx.paths.stateDir, "tasks", "history");
17966
+ if (!fs14.existsSync(src)) {
17967
+ return { name: "tasks/history/", status: "skipped", detail: "source directory not found" };
16985
17968
  }
16986
17969
  try {
16987
- const files = fs12.readdirSync(src).filter((f) => f.endsWith(".jsonl"));
17970
+ const files = fs14.readdirSync(src).filter((f) => f.endsWith(".jsonl"));
16988
17971
  if (files.length === 0) {
16989
- ctx.recordStep({ name: "tasks/history/", status: "skipped", detail: "no *.jsonl files found in source directory" });
16990
- return;
17972
+ return { name: "tasks/history/", status: "skipped", detail: "no *.jsonl files found in source directory" };
16991
17973
  }
16992
17974
  if (ctx.dryRun) {
16993
- ctx.recordStep({
17975
+ return {
16994
17976
  name: "tasks/history/",
16995
17977
  status: "success",
16996
17978
  detail: `[dry-run] would copy ${files.length} *.jsonl file(s) from ${src} \u2192 ${dest}`
16997
- });
16998
- return;
17979
+ };
16999
17980
  }
17000
17981
  ensureDir(dest);
17001
17982
  let copied = 0;
17002
17983
  let failed = 0;
17003
17984
  for (const file of files) {
17004
- const srcFile = path10.join(src, file);
17005
- const destFile = path10.join(dest, file);
17985
+ const srcFile = path12.join(src, file);
17986
+ const destFile = path12.join(dest, file);
17006
17987
  try {
17007
17988
  if (copyAndVerify(srcFile, destFile)) {
17008
17989
  copied++;
@@ -17014,119 +17995,107 @@ function migrateTaskHistory(ctx) {
17014
17995
  }
17015
17996
  }
17016
17997
  if (failed === 0) {
17017
- ctx.recordStep({
17998
+ return {
17018
17999
  name: "tasks/history/",
17019
18000
  status: "success",
17020
18001
  detail: `copied ${copied} files to ${dest} \u2014 sources left in place (delete manually when ready)`
17021
- });
17022
- } else {
17023
- ctx.recordStep({
17024
- name: "tasks/history/",
17025
- status: "failed",
17026
- detail: `copied ${copied}/${files.length} files; ${failed} failed`
17027
- });
18002
+ };
17028
18003
  }
18004
+ return {
18005
+ name: "tasks/history/",
18006
+ status: "failed",
18007
+ detail: `copied ${copied}/${files.length} files; ${failed} failed`
18008
+ };
17029
18009
  } catch (err) {
17030
18010
  const msg = err instanceof Error ? err.message : String(err);
17031
- ctx.recordStep({ name: "tasks/history/", status: "failed", detail: msg });
18011
+ return { name: "tasks/history/", status: "failed", detail: msg };
17032
18012
  }
17033
18013
  }
17034
18014
  function migrateLockfile(ctx) {
17035
- const src = path10.join(ctx.paths.configDir, "akm.lock");
17036
- const dest = path10.join(ctx.paths.dataDir, "akm.lock");
17037
- if (!fs12.existsSync(src)) {
17038
- ctx.recordStep({ name: "akm.lock", status: "skipped", detail: "source not found" });
17039
- return;
18015
+ const src = path12.join(ctx.paths.configDir, "akm.lock");
18016
+ const dest = path12.join(ctx.paths.dataDir, "akm.lock");
18017
+ if (!fs14.existsSync(src)) {
18018
+ return { name: "akm.lock", status: "skipped", detail: "source not found" };
17040
18019
  }
17041
- if (fs12.existsSync(dest)) {
17042
- ctx.recordStep({ name: "akm.lock", status: "skipped", detail: "destination already exists" });
17043
- return;
18020
+ if (fs14.existsSync(dest)) {
18021
+ return { name: "akm.lock", status: "skipped", detail: "destination already exists" };
17044
18022
  }
17045
18023
  if (ctx.dryRun) {
17046
- ctx.recordStep({ name: "akm.lock", status: "success", detail: `[dry-run] would copy ${src} \u2192 ${dest}` });
17047
- return;
18024
+ return { name: "akm.lock", status: "success", detail: `[dry-run] would copy ${src} \u2192 ${dest}` };
17048
18025
  }
17049
18026
  ensureDir(ctx.paths.dataDir);
17050
18027
  const ok = copyAndVerify(src, dest);
17051
18028
  if (ok) {
17052
- ctx.recordStep({
18029
+ return {
17053
18030
  name: "akm.lock",
17054
18031
  status: "success",
17055
18032
  detail: `copied to ${dest} \u2014 source left at ${src}.
17056
18033
  IMPORTANT: akm now reads ONLY from $DATA/akm.lock. If this step is skipped,
17057
18034
  akm will start with an empty lockfile and 'akm add' will rebuild it from scratch.`
17058
- });
17059
- } else {
17060
- ctx.recordStep({ name: "akm.lock", status: "failed", detail: `size mismatch after copy: ${src} \u2192 ${dest}` });
18035
+ };
17061
18036
  }
18037
+ return { name: "akm.lock", status: "failed", detail: `size mismatch after copy: ${src} \u2192 ${dest}` };
17062
18038
  }
17063
18039
  function migrateConfigBackups(ctx) {
17064
- const src = path10.join(ctx.paths.cacheDir, "config-backups");
17065
- const dest = path10.join(ctx.paths.dataDir, "config-backups");
17066
- if (!fs12.existsSync(src)) {
17067
- ctx.recordStep({ name: "config-backups/", status: "skipped", detail: "source directory not found" });
17068
- return;
18040
+ const src = path12.join(ctx.paths.cacheDir, "config-backups");
18041
+ const dest = path12.join(ctx.paths.dataDir, "config-backups");
18042
+ if (!fs14.existsSync(src)) {
18043
+ return { name: "config-backups/", status: "skipped", detail: "source directory not found" };
17069
18044
  }
17070
- if (fs12.existsSync(dest)) {
17071
- ctx.recordStep({ name: "config-backups/", status: "skipped", detail: "destination already exists" });
17072
- return;
18045
+ if (fs14.existsSync(dest)) {
18046
+ return { name: "config-backups/", status: "skipped", detail: "destination already exists" };
17073
18047
  }
17074
18048
  if (ctx.dryRun) {
17075
18049
  let srcCount = 0;
17076
18050
  try {
17077
18051
  srcCount = countFilesRecursive(src);
17078
18052
  } catch {}
17079
- ctx.recordStep({
18053
+ return {
17080
18054
  name: "config-backups/",
17081
18055
  status: "success",
17082
18056
  detail: `[dry-run] would recursively copy ${srcCount} file(s) from ${src} \u2192 ${dest}`
17083
- });
17084
- return;
18057
+ };
17085
18058
  }
17086
18059
  try {
17087
18060
  const srcCount = countFilesRecursive(src);
17088
- const { copied, failed } = copyDirRecursive(src, dest);
17089
- const destCount = fs12.existsSync(dest) ? countFilesRecursive(dest) : 0;
18061
+ const { copied, failed } = copyTree(src, dest, { clobber: true });
18062
+ const destCount = fs14.existsSync(dest) ? countFilesRecursive(dest) : 0;
17090
18063
  if (failed === 0 && destCount === srcCount) {
17091
- ctx.recordStep({
18064
+ return {
17092
18065
  name: "config-backups/",
17093
18066
  status: "success",
17094
18067
  detail: `copied ${copied} files to ${dest} \u2014 sources left in place (delete manually when ready)`
17095
- });
17096
- } else {
17097
- ctx.recordStep({
17098
- name: "config-backups/",
17099
- status: "failed",
17100
- detail: `file count mismatch: source ${srcCount}, destination ${destCount}; ${failed} copy errors`
17101
- });
18068
+ };
17102
18069
  }
18070
+ return {
18071
+ name: "config-backups/",
18072
+ status: "failed",
18073
+ detail: `file count mismatch: source ${srcCount}, destination ${destCount}; ${failed} copy errors`
18074
+ };
17103
18075
  } catch (err) {
17104
18076
  const msg = err instanceof Error ? err.message : String(err);
17105
- ctx.recordStep({ name: "config-backups/", status: "failed", detail: msg });
18077
+ return { name: "config-backups/", status: "failed", detail: msg };
17106
18078
  }
17107
18079
  }
17108
18080
  async function migrateTaskHistoryToDb(ctx) {
17109
- const src = path10.join(ctx.paths.cacheDir, "tasks", "history");
17110
- if (!fs12.existsSync(src)) {
17111
- ctx.recordStep({ name: "tasks/history/ \u2192 state.db", status: "skipped", detail: "source directory not found" });
17112
- return;
18081
+ const src = path12.join(ctx.paths.cacheDir, "tasks", "history");
18082
+ if (!fs14.existsSync(src)) {
18083
+ return { name: "tasks/history/ \u2192 state.db", status: "skipped", detail: "source directory not found" };
17113
18084
  }
17114
- const files = fs12.readdirSync(src).filter((f) => f.endsWith(".jsonl"));
18085
+ const files = fs14.readdirSync(src).filter((f) => f.endsWith(".jsonl"));
17115
18086
  if (files.length === 0) {
17116
- ctx.recordStep({
18087
+ return {
17117
18088
  name: "tasks/history/ \u2192 state.db",
17118
18089
  status: "skipped",
17119
18090
  detail: "no *.jsonl files found in source directory"
17120
- });
17121
- return;
18091
+ };
17122
18092
  }
17123
18093
  if (ctx.dryRun) {
17124
- ctx.recordStep({
18094
+ return {
17125
18095
  name: "tasks/history/ \u2192 state.db",
17126
18096
  status: "success",
17127
18097
  detail: `[dry-run] would parse ${files.length} *.jsonl file(s) and import rows into ${ctx.paths.stateDbPath}`
17128
- });
17129
- return;
18098
+ };
17130
18099
  }
17131
18100
  try {
17132
18101
  ensureDir(ctx.paths.dataDir);
@@ -17136,8 +18105,8 @@ async function migrateTaskHistoryToDb(ctx) {
17136
18105
  let failed = 0;
17137
18106
  try {
17138
18107
  for (const file of files) {
17139
- const filePath = path10.join(src, file);
17140
- const text = fs12.readFileSync(filePath, "utf8");
18108
+ const filePath = path12.join(src, file);
18109
+ const text = fs14.readFileSync(filePath, "utf8");
17141
18110
  const lines = text.split(`
17142
18111
  `).filter((l) => l.trim().length > 0);
17143
18112
  db.exec("BEGIN");
@@ -17179,33 +18148,30 @@ async function migrateTaskHistoryToDb(ctx) {
17179
18148
  db.close();
17180
18149
  }
17181
18150
  if (failed === 0) {
17182
- ctx.recordStep({
18151
+ return {
17183
18152
  name: "tasks/history/ \u2192 state.db",
17184
18153
  status: "success",
17185
18154
  detail: `imported ${imported} task history row(s) from ${files.length} JSONL file(s) into state.db \u2014 sources left in place (delete manually when ready)`
17186
- });
17187
- } else {
17188
- ctx.recordStep({
17189
- name: "tasks/history/ \u2192 state.db",
17190
- status: "failed",
17191
- detail: `imported ${imported} row(s); ${failed} line(s) could not be parsed`
17192
- });
18155
+ };
17193
18156
  }
18157
+ return {
18158
+ name: "tasks/history/ \u2192 state.db",
18159
+ status: "failed",
18160
+ detail: `imported ${imported} row(s); ${failed} line(s) could not be parsed`
18161
+ };
17194
18162
  } catch (err) {
17195
18163
  const msg = err instanceof Error ? err.message : String(err);
17196
- ctx.recordStep({ name: "tasks/history/ \u2192 state.db", status: "failed", detail: msg });
18164
+ return { name: "tasks/history/ \u2192 state.db", status: "failed", detail: msg };
17197
18165
  }
17198
18166
  }
17199
18167
  function noteRegistryIndexCache(ctx) {
17200
- const src = path10.join(ctx.paths.cacheDir, "registry-index");
17201
- if (!fs12.existsSync(src)) {
17202
- ctx.recordStep({ name: "registry-index/ (note)", status: "skipped", detail: "no old $CACHE/registry-index/ directory found" });
17203
- return;
18168
+ const src = path12.join(ctx.paths.cacheDir, "registry-index");
18169
+ if (!fs14.existsSync(src)) {
18170
+ return { name: "registry-index/ (note)", status: "skipped", detail: "no old $CACHE/registry-index/ directory found" };
17204
18171
  }
17205
- const legacyFiles = fs12.readdirSync(src).filter((f) => f.endsWith(".json") && !f.startsWith("website-"));
18172
+ const legacyFiles = fs14.readdirSync(src).filter((f) => f.endsWith(".json") && !f.startsWith("website-"));
17206
18173
  if (legacyFiles.length === 0) {
17207
- ctx.recordStep({ name: "registry-index/ (note)", status: "skipped", detail: "no old *.json cache files found" });
17208
- return;
18174
+ return { name: "registry-index/ (note)", status: "skipped", detail: "no old *.json cache files found" };
17209
18175
  }
17210
18176
  if (!ctx.dryRun) {
17211
18177
  console.log(`
@@ -17213,57 +18179,57 @@ function noteRegistryIndexCache(ctx) {
17213
18179
  These are ignored in v0.9 \u2014 data is now stored in the registry_index_cache` + `
17214
18180
  table in $DATA/index.db and will be rebuilt on next 'akm registry search'.
17215
18181
  You may safely delete these files after migration:
17216
- ` + legacyFiles.map((f) => ` ${path10.join(src, f)}`).join(`
18182
+ ` + legacyFiles.map((f) => ` ${path12.join(src, f)}`).join(`
17217
18183
  `));
17218
18184
  }
17219
- ctx.recordStep({
18185
+ return {
17220
18186
  name: "registry-index/ (note)",
17221
18187
  status: "success",
17222
18188
  detail: `${legacyFiles.length} old file(s) noted at ${src} \u2014 registry index cache will be rebuilt on next ` + `'akm registry search'. Safe to delete: ${src}/*.json`
17223
- });
18189
+ };
17224
18190
  }
17225
18191
  var v07To08Migration = {
17226
18192
  label: "0.7 \u2192 0.8",
17227
18193
  sourceVersion: "0.7",
17228
18194
  isNeeded: (paths) => {
17229
18195
  const candidates = [
17230
- path10.join(paths.cacheDir, "index.db"),
17231
- path10.join(paths.cacheDir, "workflow.db"),
17232
- path10.join(paths.cacheDir, "events.jsonl"),
17233
- path10.join(paths.cacheDir, "tasks", "history"),
17234
- path10.join(paths.configDir, "akm.lock"),
17235
- path10.join(paths.cacheDir, "config-backups"),
17236
- path10.join(paths.cacheDir, "registry-index")
18196
+ path12.join(paths.cacheDir, "index.db"),
18197
+ path12.join(paths.cacheDir, "workflow.db"),
18198
+ path12.join(paths.cacheDir, "events.jsonl"),
18199
+ path12.join(paths.cacheDir, "tasks", "history"),
18200
+ path12.join(paths.configDir, "akm.lock"),
18201
+ path12.join(paths.cacheDir, "config-backups"),
18202
+ path12.join(paths.cacheDir, "registry-index")
17237
18203
  ];
17238
- return candidates.some((p) => fs12.existsSync(p));
18204
+ return candidates.some((p) => fs14.existsSync(p));
17239
18205
  },
17240
- run: async (ctx) => {
17241
- migrateDb(ctx, "index.db");
17242
- migrateDb(ctx, "workflow.db");
17243
- await migrateEventsJsonl(ctx);
17244
- migrateTaskHistory(ctx);
17245
- migrateLockfile(ctx);
17246
- migrateConfigBackups(ctx);
17247
- await migrateTaskHistoryToDb(ctx);
17248
- noteRegistryIndexCache(ctx);
17249
- }
18206
+ steps: [
18207
+ { id: "index-db", title: "index.db", run: (ctx) => migrateDb(ctx, "index.db") },
18208
+ { id: "workflow-db", title: "workflow.db", run: (ctx) => migrateDb(ctx, "workflow.db") },
18209
+ { id: "events-jsonl", title: "events.jsonl \u2192 state.db", run: migrateEventsJsonl },
18210
+ { id: "tasks-history-files", title: "tasks/history/", run: migrateTaskHistory },
18211
+ { id: "lockfile", title: "akm.lock", run: migrateLockfile },
18212
+ { id: "config-backups", title: "config-backups/", run: migrateConfigBackups },
18213
+ { id: "tasks-history-db", title: "tasks/history/ \u2192 state.db", run: migrateTaskHistoryToDb },
18214
+ { id: "registry-index-note", title: "registry-index/ (note)", run: noteRegistryIndexCache }
18215
+ ]
17250
18216
  };
17251
18217
  function legacyGraphCandidatePaths(ctx) {
17252
18218
  return [
17253
- path10.join(ctx.paths.cacheDir, "graph-snapshot.json"),
17254
- path10.join(ctx.paths.dataDir, "graph-snapshot.json"),
17255
- path10.join(ctx.paths.dataDir, "graph-export.json")
18219
+ path12.join(ctx.paths.cacheDir, "graph-snapshot.json"),
18220
+ path12.join(ctx.paths.dataDir, "graph-snapshot.json"),
18221
+ path12.join(ctx.paths.dataDir, "graph-export.json")
17256
18222
  ];
17257
18223
  }
17258
18224
  function findLegacyGraphFile(ctx) {
17259
18225
  for (const candidate of legacyGraphCandidatePaths(ctx)) {
17260
- if (fs12.existsSync(candidate) && fs12.statSync(candidate).isFile())
18226
+ if (fs14.existsSync(candidate) && fs14.statSync(candidate).isFile())
17261
18227
  return candidate;
17262
18228
  }
17263
- const graphDir = path10.join(ctx.paths.cacheDir, "graph");
17264
- if (fs12.existsSync(graphDir) && fs12.statSync(graphDir).isDirectory()) {
18229
+ const graphDir = path12.join(ctx.paths.cacheDir, "graph");
18230
+ if (fs14.existsSync(graphDir) && fs14.statSync(graphDir).isDirectory()) {
17265
18231
  try {
17266
- const json = fs12.readdirSync(graphDir).filter((f) => f.endsWith(".json")).map((f) => path10.join(graphDir, f));
18232
+ const json = fs14.readdirSync(graphDir).filter((f) => f.endsWith(".json")).map((f) => path12.join(graphDir, f));
17267
18233
  if (json.length > 0)
17268
18234
  return json[0];
17269
18235
  } catch {}
@@ -17297,43 +18263,38 @@ async function migrateGraphFileToDb(ctx) {
17297
18263
  const name = "Graph snapshot import";
17298
18264
  const legacyFile = findLegacyGraphFile(ctx);
17299
18265
  if (!legacyFile) {
17300
- ctx.recordStep({ name, status: "skipped", detail: "no legacy graph file found" });
17301
- return;
18266
+ return { name, status: "skipped", detail: "no legacy graph file found" };
17302
18267
  }
17303
- if (!fs12.existsSync(ctx.paths.indexDbPath)) {
17304
- ctx.recordStep({
18268
+ if (!fs14.existsSync(ctx.paths.indexDbPath)) {
18269
+ return {
17305
18270
  name,
17306
18271
  status: "skipped",
17307
18272
  detail: `index.db not found at ${ctx.paths.indexDbPath}; run akm to initialize, then re-run this migration`
17308
- });
17309
- return;
18273
+ };
17310
18274
  }
17311
18275
  if (ctx.dryRun) {
17312
- ctx.recordStep({
18276
+ return {
17313
18277
  name,
17314
18278
  status: "success",
17315
18279
  detail: `[dry-run] would parse ${legacyFile} and import into ${ctx.paths.indexDbPath} graph tables`
17316
- });
17317
- return;
18280
+ };
17318
18281
  }
17319
18282
  try {
17320
- const raw = fs12.readFileSync(legacyFile, "utf8");
18283
+ const raw = fs14.readFileSync(legacyFile, "utf8");
17321
18284
  let parsed;
17322
18285
  try {
17323
18286
  parsed = JSON.parse(raw);
17324
18287
  } catch (err) {
17325
18288
  const msg = err instanceof Error ? err.message : String(err);
17326
- ctx.recordStep({ name, status: "failed", detail: `${legacyFile} is not valid JSON: ${msg}` });
17327
- return;
18289
+ return { name, status: "failed", detail: `${legacyFile} is not valid JSON: ${msg}` };
17328
18290
  }
17329
18291
  const validation = validateGraphSnapshot(parsed);
17330
18292
  if (!validation.ok) {
17331
- ctx.recordStep({
18293
+ return {
17332
18294
  name,
17333
18295
  status: "failed",
17334
18296
  detail: `${legacyFile} does not match expected GraphSnapshot shape: ${validation.reason}`
17335
- });
17336
- return;
18297
+ };
17337
18298
  }
17338
18299
  const snapshot = validation.data;
17339
18300
  const { openExistingDatabase: openExistingDatabase2, closeDatabase: closeDatabase2 } = await Promise.resolve().then(() => (init_db(), exports_db));
@@ -17381,51 +18342,48 @@ async function migrateGraphFileToDb(ctx) {
17381
18342
  const importedCount = db.prepare("SELECT COUNT(*) AS cnt FROM graph_files WHERE stash_root = ?").get(snapshot.stashRoot).cnt;
17382
18343
  const meta = loadStoredGraphMeta2(snapshot.stashRoot, db);
17383
18344
  if (!meta) {
17384
- ctx.recordStep({
18345
+ return {
17385
18346
  name,
17386
18347
  status: "failed",
17387
18348
  detail: `import did not produce a graph_meta row for stash ${snapshot.stashRoot}`
17388
- });
17389
- return;
18349
+ };
17390
18350
  }
17391
18351
  if (importedCount === 0) {
17392
- ctx.recordStep({
18352
+ return {
17393
18353
  name,
17394
18354
  status: "failed",
17395
18355
  detail: `import produced zero graph_files rows for stash ${snapshot.stashRoot} \u2014 ` + `the entries table has no matching paths. Run "akm index" first, then retry the migration. Source file ${legacyFile} was NOT renamed.`
17396
- });
17397
- return;
18356
+ };
17398
18357
  }
17399
18358
  const renamed = `${legacyFile}.migrated`;
17400
18359
  try {
17401
- fs12.renameSync(legacyFile, renamed);
18360
+ fs14.renameSync(legacyFile, renamed);
17402
18361
  } catch (err) {
17403
18362
  const msg = err instanceof Error ? err.message : String(err);
17404
- ctx.recordStep({
18363
+ return {
17405
18364
  name,
17406
18365
  status: "success",
17407
18366
  detail: `imported graph for ${snapshot.stashRoot} into ${ctx.paths.indexDbPath} but could not rename ${legacyFile}: ${msg}`
17408
- });
17409
- return;
18367
+ };
17410
18368
  }
17411
- ctx.recordStep({
18369
+ return {
17412
18370
  name,
17413
18371
  status: "success",
17414
18372
  detail: `imported graph snapshot from ${legacyFile} into ${ctx.paths.indexDbPath} (stash ${snapshot.stashRoot}; ${importedCount} file(s) imported of ${graph.files.length} in source). Source renamed to ${renamed} \u2014 delete manually when ready.`
17415
- });
18373
+ };
17416
18374
  } finally {
17417
18375
  closeDatabase2(db);
17418
18376
  }
17419
18377
  } catch (err) {
17420
18378
  const msg = err instanceof Error ? err.message : String(err);
17421
- ctx.recordStep({ name, status: "failed", detail: msg });
18379
+ return { name, status: "failed", detail: msg };
17422
18380
  }
17423
18381
  }
17424
18382
  function resolvePrimaryStashDir(configDirPath) {
17425
18383
  try {
17426
- const cfgPath = path10.join(configDirPath, "config.json");
17427
- if (fs12.existsSync(cfgPath)) {
17428
- const cfg = JSON.parse(fs12.readFileSync(cfgPath, "utf8"));
18384
+ const cfgPath = path12.join(configDirPath, "config.json");
18385
+ if (fs14.existsSync(cfgPath)) {
18386
+ const cfg = JSON.parse(fs14.readFileSync(cfgPath, "utf8"));
17429
18387
  if (typeof cfg.stashDir === "string" && cfg.stashDir.length > 0)
17430
18388
  return cfg.stashDir;
17431
18389
  }
@@ -17434,8 +18392,8 @@ function resolvePrimaryStashDir(configDirPath) {
17434
18392
  }
17435
18393
  function countEnvFilesRecursive(dir) {
17436
18394
  let count = 0;
17437
- for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
17438
- const full = path10.join(dir, entry.name);
18395
+ for (const entry of fs14.readdirSync(dir, { withFileTypes: true })) {
18396
+ const full = path12.join(dir, entry.name);
17439
18397
  if (entry.isDirectory()) {
17440
18398
  count += countEnvFilesRecursive(full);
17441
18399
  } else if (entry.name === ".env" || entry.name.endsWith(".env")) {
@@ -17444,46 +18402,16 @@ function countEnvFilesRecursive(dir) {
17444
18402
  }
17445
18403
  return count;
17446
18404
  }
17447
- function copyDirNoClobber(src, dest) {
17448
- let copied = 0;
17449
- let skipped = 0;
17450
- let failed = 0;
17451
- ensureDir(dest);
17452
- for (const entry of fs12.readdirSync(src, { withFileTypes: true })) {
17453
- const srcEntry = path10.join(src, entry.name);
17454
- const destEntry = path10.join(dest, entry.name);
17455
- if (entry.isDirectory()) {
17456
- const sub = copyDirNoClobber(srcEntry, destEntry);
17457
- copied += sub.copied;
17458
- skipped += sub.skipped;
17459
- failed += sub.failed;
17460
- continue;
17461
- }
17462
- if (fs12.existsSync(destEntry)) {
17463
- skipped++;
17464
- continue;
17465
- }
17466
- try {
17467
- if (copyAndVerify(srcEntry, destEntry))
17468
- copied++;
17469
- else
17470
- failed++;
17471
- } catch {
17472
- failed++;
17473
- }
17474
- }
17475
- return { copied, skipped, failed };
17476
- }
17477
18405
  function chmodTreeSecure(dir) {
17478
18406
  const isWin = process.platform === "win32";
17479
18407
  try {
17480
- fs12.chmodSync(dir, 448);
18408
+ fs14.chmodSync(dir, 448);
17481
18409
  } catch (err) {
17482
18410
  if (!isWin)
17483
18411
  return { ok: false, detail: `chmod 0700 ${dir} failed: ${err instanceof Error ? err.message : err}` };
17484
18412
  }
17485
- for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
17486
- const full = path10.join(dir, entry.name);
18413
+ for (const entry of fs14.readdirSync(dir, { withFileTypes: true })) {
18414
+ const full = path12.join(dir, entry.name);
17487
18415
  if (entry.isDirectory()) {
17488
18416
  const sub = chmodTreeSecure(full);
17489
18417
  if (!sub.ok)
@@ -17491,8 +18419,8 @@ function chmodTreeSecure(dir) {
17491
18419
  continue;
17492
18420
  }
17493
18421
  try {
17494
- fs12.chmodSync(full, 384);
17495
- if (!isWin && (fs12.statSync(full).mode & 511) !== 384) {
18422
+ fs14.chmodSync(full, 384);
18423
+ if (!isWin && (fs14.statSync(full).mode & 511) !== 384) {
17496
18424
  return { ok: false, detail: `mode verification failed for ${full}` };
17497
18425
  }
17498
18426
  } catch (err) {
@@ -17505,59 +18433,52 @@ function chmodTreeSecure(dir) {
17505
18433
  async function migrateVaultsToEnv(ctx) {
17506
18434
  const name = "vaults/ \u2192 env/";
17507
18435
  const stashDir = resolvePrimaryStashDir(ctx.paths.configDir);
17508
- const vaultsDir = path10.join(stashDir, "vaults");
17509
- const envDir = path10.join(stashDir, "env");
17510
- const marker = path10.join(vaultsDir, ".migrated");
17511
- if (!fs12.existsSync(vaultsDir)) {
17512
- ctx.recordStep({ name, status: "skipped", detail: `no vaults/ directory under ${stashDir}` });
17513
- return;
18436
+ const vaultsDir = path12.join(stashDir, "vaults");
18437
+ const envDir = path12.join(stashDir, "env");
18438
+ const marker = path12.join(vaultsDir, MIGRATED_MARKER);
18439
+ if (!fs14.existsSync(vaultsDir)) {
18440
+ return { name, status: "skipped", detail: `no vaults/ directory under ${stashDir}` };
17514
18441
  }
17515
- if (fs12.existsSync(marker)) {
17516
- ctx.recordStep({ name, status: "skipped", detail: "already migrated (.migrated marker present)" });
17517
- return;
18442
+ if (fs14.existsSync(marker)) {
18443
+ return { name, status: "skipped", detail: "already migrated (.migrated marker present)" };
17518
18444
  }
17519
18445
  const vaultEnvCount = countEnvFilesRecursive(vaultsDir);
17520
18446
  if (vaultEnvCount === 0) {
17521
- ctx.recordStep({ name, status: "skipped", detail: "vaults/ has no .env files to migrate" });
17522
- return;
18447
+ return { name, status: "skipped", detail: "vaults/ has no .env files to migrate" };
17523
18448
  }
17524
18449
  if (ctx.dryRun) {
17525
- ctx.recordStep({
18450
+ return {
17526
18451
  name,
17527
18452
  status: "success",
17528
18453
  detail: `[dry-run] would copy ${vaultEnvCount} .env file(s) ${vaultsDir} \u2192 ${envDir}, chmod 0600/0700, and write ${marker}`
17529
- });
17530
- return;
18454
+ };
17531
18455
  }
17532
18456
  try {
17533
- const { copied, skipped, failed } = copyDirNoClobber(vaultsDir, envDir);
18457
+ const { copied, skipped, failed } = copyTree(vaultsDir, envDir, { clobber: false });
17534
18458
  if (failed > 0) {
17535
- ctx.recordStep({ name, status: "failed", detail: `${failed} file(s) failed to copy; env/ left as-is, no marker written` });
17536
- return;
18459
+ return { name, status: "failed", detail: `${failed} file(s) failed to copy; env/ left as-is, no marker written` };
17537
18460
  }
17538
18461
  const chmodRes = chmodTreeSecure(envDir);
17539
18462
  if (!chmodRes.ok) {
17540
- ctx.recordStep({ name, status: "failed", detail: chmodRes.detail ?? "permission tightening failed" });
17541
- return;
18463
+ return { name, status: "failed", detail: chmodRes.detail ?? "permission tightening failed" };
17542
18464
  }
17543
18465
  const envEnvCount = countEnvFilesRecursive(envDir);
17544
18466
  if (envEnvCount < vaultEnvCount) {
17545
- ctx.recordStep({
18467
+ return {
17546
18468
  name,
17547
18469
  status: "failed",
17548
18470
  detail: `post-copy count ${envEnvCount} < source ${vaultEnvCount}; no marker written`
17549
- });
17550
- return;
18471
+ };
17551
18472
  }
17552
- fs12.writeFileSync(marker, `migrated vaults/ -> env/ at ${new Date().toISOString()}
18473
+ fs14.writeFileSync(marker, `migrated vaults/ -> env/ at ${new Date().toISOString()}
17553
18474
  `, { mode: 384 });
17554
- ctx.recordStep({
18475
+ return {
17555
18476
  name,
17556
18477
  status: "success",
17557
18478
  detail: `copied ${copied} file(s) (${skipped} already present in env/, preserved) ${vaultsDir} \u2192 ${envDir}; vaults/ left intact as a frozen copy. Run \`akm index\` to refresh search.`
17558
- });
18479
+ };
17559
18480
  } catch (err) {
17560
- ctx.recordStep({ name, status: "failed", detail: err instanceof Error ? err.message : String(err) });
18481
+ return { name, status: "failed", detail: err instanceof Error ? err.message : String(err) };
17561
18482
  }
17562
18483
  }
17563
18484
  var v08To09Migration = {
@@ -17566,10 +18487,10 @@ var v08To09Migration = {
17566
18487
  isNeeded: (_paths) => {
17567
18488
  return true;
17568
18489
  },
17569
- run: async (ctx) => {
17570
- await migrateGraphFileToDb(ctx);
17571
- await migrateVaultsToEnv(ctx);
17572
- }
18490
+ steps: [
18491
+ { id: "graph-snapshot-import", title: "Graph snapshot import", run: migrateGraphFileToDb },
18492
+ { id: "vaults-to-env", title: "vaults/ \u2192 env/", run: migrateVaultsToEnv }
18493
+ ]
17573
18494
  };
17574
18495
  var MIGRATIONS2 = [v07To08Migration, v08To09Migration];
17575
18496
  async function confirm() {
@@ -17655,12 +18576,12 @@ task_history: task_id PK).
17655
18576
  Migration complete. No errors.`);
17656
18577
  console.log(`
17657
18578
  Old files at the original locations are safe to delete manually after verifying akm works:
17658
- ${path10.join(cacheDir, "index.db")}
17659
- ${path10.join(cacheDir, "workflow.db")}
17660
- ${path10.join(cacheDir, "events.jsonl")}
17661
- ${path10.join(cacheDir, "tasks", "history")}
17662
- ${path10.join(cacheDir, "config-backups")}
17663
- ${path10.join(configDir, "akm.lock")}
18579
+ ${path12.join(cacheDir, "index.db")}
18580
+ ${path12.join(cacheDir, "workflow.db")}
18581
+ ${path12.join(cacheDir, "events.jsonl")}
18582
+ ${path12.join(cacheDir, "tasks", "history")}
18583
+ ${path12.join(cacheDir, "config-backups")}
18584
+ ${path12.join(configDir, "akm.lock")}
17664
18585
 
17665
18586
  Next step \u2014 repopulate graph data (if migrating from 0.7):
17666
18587
  The 0.8.0 graph schema redesign (DB_VERSION 12 \u2192 13) rebuilds the graph
@@ -17672,7 +18593,7 @@ Next step \u2014 repopulate graph data (if migrating from 0.7):
17672
18593
  docs/migration/v0.7-to-v0.8.md#graph-extraction-will-re-run-after-upgrade.
17673
18594
  `);
17674
18595
  }
17675
- async function runMigrations2(opts = { dryRun: DRY_RUN }) {
18596
+ async function runMigrations3(opts = { dryRun: DRY_RUN }) {
17676
18597
  const paths = opts.paths ?? PATHS;
17677
18598
  const reports = [];
17678
18599
  const migrations = filteredMigrations();
@@ -17701,7 +18622,7 @@ async function runMigrations2(opts = { dryRun: DRY_RUN }) {
17701
18622
  continue;
17702
18623
  }
17703
18624
  try {
17704
- await migration.run(ctx);
18625
+ await runSteps(migration.steps, ctx);
17705
18626
  reports.push({ label: migration.label, ran: true, results: stepResults });
17706
18627
  } catch (err) {
17707
18628
  const msg = err instanceof Error ? err.message : String(err);
@@ -17740,7 +18661,7 @@ async function main() {
17740
18661
  console.log(`[dry-run] No changes will be written.
17741
18662
  `);
17742
18663
  }
17743
- const reports = await runMigrations2({ dryRun: DRY_RUN, paths: PATHS });
18664
+ const reports = await runMigrations3({ dryRun: DRY_RUN, paths: PATHS });
17744
18665
  versionReports.push(...reports);
17745
18666
  printGroupedSummary();
17746
18667
  if (DRY_RUN) {
@@ -17753,7 +18674,7 @@ var invokedDirectly = (() => {
17753
18674
  if (!entry)
17754
18675
  return false;
17755
18676
  const here = new URL(import.meta.url).pathname;
17756
- return path10.resolve(entry) === here;
18677
+ return path12.resolve(entry) === here;
17757
18678
  } catch {
17758
18679
  return false;
17759
18680
  }
@@ -17762,6 +18683,6 @@ if (invokedDirectly) {
17762
18683
  await main();
17763
18684
  }
17764
18685
  export {
17765
- runMigrations2 as runMigrations,
18686
+ runMigrations3 as runMigrations,
17766
18687
  MIGRATIONS2 as MIGRATIONS
17767
18688
  };