akm-cli 0.8.7 → 0.8.14

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 (324) hide show
  1. package/CHANGELOG.md +428 -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/assets/templates/html/default.html +78 -0
  16. package/dist/assets/templates/html/health.html +560 -0
  17. package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
  18. package/dist/cli/config-migrate.js +6 -6
  19. package/dist/cli/config-validate.js +4 -4
  20. package/dist/cli/confirm.js +3 -3
  21. package/dist/cli/parse-args.js +1 -1
  22. package/dist/cli/shared.js +72 -19
  23. package/dist/cli-node.mjs +26 -0
  24. package/dist/cli.js +206 -3866
  25. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  26. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  27. package/dist/commands/agent/contribute-cli.js +200 -0
  28. package/dist/commands/completions.js +1 -1
  29. package/dist/commands/config-cli.js +230 -3
  30. package/dist/commands/db-cli.js +2 -2
  31. package/dist/commands/env/env-cli.js +529 -0
  32. package/dist/commands/env/env.js +410 -0
  33. package/dist/commands/env/secret-cli.js +259 -0
  34. package/dist/commands/{secret.js → env/secret.js} +6 -47
  35. package/dist/commands/events.js +4 -4
  36. package/dist/commands/feedback-cli.js +18 -34
  37. package/dist/commands/graph/graph-cli.js +132 -0
  38. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  39. package/dist/commands/health/checks.js +279 -0
  40. package/dist/commands/health/html-report.js +448 -0
  41. package/dist/commands/health.js +189 -266
  42. package/dist/commands/{consolidate.js → improve/consolidate.js} +48 -36
  43. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  44. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  45. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  46. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  47. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  48. package/dist/commands/{extract.js → improve/extract.js} +221 -26
  49. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
  50. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
  51. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  52. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
  53. package/dist/commands/{improve.js → improve/improve.js} +672 -292
  54. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  55. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  56. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  57. package/dist/commands/improve/reflect-noise.js +0 -0
  58. package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
  59. package/dist/commands/improve/session-asset.js +248 -0
  60. package/dist/commands/lint/agent-linter.js +1 -1
  61. package/dist/commands/lint/base-linter.js +55 -37
  62. package/dist/commands/lint/command-linter.js +1 -1
  63. package/dist/commands/lint/default-linter.js +1 -1
  64. package/dist/commands/lint/env-key-rules.js +1 -1
  65. package/dist/commands/lint/index.js +19 -25
  66. package/dist/commands/lint/knowledge-linter.js +1 -1
  67. package/dist/commands/lint/memory-linter.js +1 -1
  68. package/dist/commands/lint/registry.js +8 -8
  69. package/dist/commands/lint/skill-linter.js +1 -1
  70. package/dist/commands/lint/task-linter.js +1 -1
  71. package/dist/commands/lint/workflow-linter.js +1 -1
  72. package/dist/commands/lint.js +1 -1
  73. package/dist/commands/observability-cli.js +244 -0
  74. package/dist/commands/proposal/drain-policies.js +3 -3
  75. package/dist/commands/proposal/drain.js +87 -15
  76. package/dist/commands/proposal/proposal-cli.js +490 -0
  77. package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
  78. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  79. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  80. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  81. package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
  82. package/dist/commands/{curate.js → read/curate.js} +7 -7
  83. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  84. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  85. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  86. package/dist/commands/read/search-cli.js +207 -0
  87. package/dist/commands/{search.js → read/search.js} +22 -27
  88. package/dist/commands/{show.js → read/show.js} +31 -45
  89. package/dist/commands/registry-cli.js +8 -8
  90. package/dist/commands/remember.js +14 -10
  91. package/dist/commands/sources/add-cli.js +293 -0
  92. package/dist/commands/{history.js → sources/history.js} +27 -25
  93. package/dist/commands/{info.js → sources/info.js} +6 -6
  94. package/dist/commands/{init.js → sources/init.js} +6 -6
  95. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  96. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  97. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  98. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  99. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  100. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  101. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  102. package/dist/commands/sources/sources-cli.js +305 -0
  103. package/dist/commands/sources/stash-cli.js +219 -0
  104. package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
  105. package/dist/commands/tasks/default-tasks.js +173 -0
  106. package/dist/commands/tasks/tasks-cli.js +210 -0
  107. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  108. package/dist/commands/wiki-cli.js +307 -0
  109. package/dist/commands/workflow-cli.js +329 -0
  110. package/dist/core/action-contributors.js +1 -1
  111. package/dist/core/assert.js +40 -0
  112. package/dist/core/asset/asset-create.js +54 -0
  113. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  114. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  115. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  116. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  117. package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
  118. package/dist/core/best-effort.js +64 -0
  119. package/dist/core/common.js +32 -18
  120. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  121. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  122. package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
  123. package/dist/core/config/config-types.js +16 -0
  124. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  125. package/dist/core/{config.js → config/config.js} +10 -8
  126. package/dist/core/env-secret-ref.js +90 -0
  127. package/dist/core/errors.js +13 -3
  128. package/dist/core/events.js +27 -4
  129. package/dist/core/file-lock.js +1 -1
  130. package/dist/core/improve-types.js +48 -0
  131. package/dist/core/lesson-lint.js +2 -2
  132. package/dist/core/logs-db.js +304 -0
  133. package/dist/core/paths.js +2 -2
  134. package/dist/core/ripgrep/install.js +2 -2
  135. package/dist/core/ripgrep/resolve.js +2 -2
  136. package/dist/core/state-db.js +195 -60
  137. package/dist/core/text-truncation.js +148 -0
  138. package/dist/core/time.js +1 -1
  139. package/dist/core/write-source.js +98 -85
  140. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  141. package/dist/indexer/{db.js → db/db.js} +128 -118
  142. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  143. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  144. package/dist/indexer/ensure-index.js +4 -4
  145. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  146. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  147. package/dist/indexer/indexer.js +37 -30
  148. package/dist/indexer/init.js +54 -0
  149. package/dist/indexer/manifest.js +10 -10
  150. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
  151. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  152. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  153. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  154. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  155. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  156. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  157. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  158. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  159. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  160. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  161. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  162. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  163. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  164. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  165. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  166. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  167. package/dist/integrations/agent/builder-shared.js +39 -0
  168. package/dist/integrations/agent/builders.js +14 -81
  169. package/dist/integrations/agent/config.js +6 -4
  170. package/dist/integrations/agent/detect.js +1 -1
  171. package/dist/integrations/agent/index.js +23 -8
  172. package/dist/integrations/agent/prompts.js +2 -3
  173. package/dist/integrations/agent/runner.js +22 -3
  174. package/dist/integrations/agent/spawn.js +9 -10
  175. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  176. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  177. package/dist/integrations/harnesses/claude/index.js +64 -0
  178. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
  179. package/dist/integrations/harnesses/index.js +144 -0
  180. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  181. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  182. package/dist/integrations/harnesses/opencode/index.js +59 -0
  183. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  184. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  185. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  186. package/dist/integrations/harnesses/types.js +43 -0
  187. package/dist/integrations/lockfile.js +7 -16
  188. package/dist/integrations/session-logs/index.js +82 -9
  189. package/dist/llm/call-ai.js +4 -4
  190. package/dist/llm/client.js +146 -6
  191. package/dist/llm/embedder.js +6 -6
  192. package/dist/llm/embedders/local.js +9 -22
  193. package/dist/llm/embedders/remote.js +2 -2
  194. package/dist/llm/embedders/types.js +1 -1
  195. package/dist/llm/graph-extract.js +31 -12
  196. package/dist/llm/index-passes.js +1 -1
  197. package/dist/llm/memory-infer.js +12 -5
  198. package/dist/llm/metadata-enhance.js +2 -2
  199. package/dist/llm/usage-persist.js +77 -0
  200. package/dist/llm/usage-telemetry.js +103 -0
  201. package/dist/output/context.js +9 -46
  202. package/dist/output/html-render.js +73 -0
  203. package/dist/output/renderers.js +88 -58
  204. package/dist/output/shapes/curate.js +7 -3
  205. package/dist/output/shapes/distill.js +7 -3
  206. package/dist/output/shapes/env-list.js +18 -16
  207. package/dist/output/shapes/events.js +5 -4
  208. package/dist/output/shapes/helpers.js +19 -5
  209. package/dist/output/shapes/history.js +7 -3
  210. package/dist/output/shapes/passthrough.js +8 -11
  211. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  212. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  213. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  214. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  215. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  216. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  217. package/dist/output/shapes/registry-search.js +7 -3
  218. package/dist/output/shapes/registry.js +12 -0
  219. package/dist/output/shapes/search.js +7 -3
  220. package/dist/output/shapes/secret-list.js +18 -16
  221. package/dist/output/shapes/show.js +7 -3
  222. package/dist/output/shapes.js +55 -30
  223. package/dist/output/text/add.js +2 -3
  224. package/dist/output/text/clone.js +2 -3
  225. package/dist/output/text/config.js +2 -3
  226. package/dist/output/text/curate.js +4 -3
  227. package/dist/output/text/distill.js +2 -3
  228. package/dist/output/text/enable-disable.js +5 -4
  229. package/dist/output/text/env.js +13 -0
  230. package/dist/output/text/events.js +5 -4
  231. package/dist/output/text/feedback.js +4 -3
  232. package/dist/output/text/helpers.js +123 -40
  233. package/dist/output/text/history.js +2 -3
  234. package/dist/output/text/import.js +2 -3
  235. package/dist/output/text/index.js +2 -3
  236. package/dist/output/text/info.js +2 -3
  237. package/dist/output/text/init.js +2 -3
  238. package/dist/output/text/list.js +2 -3
  239. package/dist/output/text/proposal/producer.js +9 -0
  240. package/dist/output/text/proposal/proposal.js +13 -0
  241. package/dist/output/text/registry-commands.js +8 -7
  242. package/dist/output/text/registry.js +12 -0
  243. package/dist/output/text/remember.js +4 -3
  244. package/dist/output/text/remove.js +2 -3
  245. package/dist/output/text/save.js +2 -3
  246. package/dist/output/text/search.js +4 -3
  247. package/dist/output/text/show.js +4 -3
  248. package/dist/output/text/update.js +2 -3
  249. package/dist/output/text/upgrade.js +2 -3
  250. package/dist/output/text/wiki.js +12 -11
  251. package/dist/output/text/workflow.js +12 -10
  252. package/dist/output/text.js +66 -32
  253. package/dist/registry/build-index.js +11 -10
  254. package/dist/registry/factory.js +1 -1
  255. package/dist/registry/origin-resolve.js +1 -1
  256. package/dist/registry/providers/index.js +2 -2
  257. package/dist/registry/providers/skills-sh.js +91 -72
  258. package/dist/registry/providers/static-index.js +75 -52
  259. package/dist/registry/resolve.js +3 -3
  260. package/dist/runtime.js +242 -0
  261. package/dist/scripts/migrate-storage.js +1654 -683
  262. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
  263. package/dist/setup/detect.js +311 -9
  264. package/dist/setup/harness-config-import.js +6 -120
  265. package/dist/setup/setup.js +454 -43
  266. package/dist/sources/include.js +1 -1
  267. package/dist/sources/provider-factory.js +2 -2
  268. package/dist/sources/providers/filesystem.js +3 -3
  269. package/dist/sources/providers/git.js +9 -9
  270. package/dist/sources/providers/index.js +4 -4
  271. package/dist/sources/providers/npm.js +6 -6
  272. package/dist/sources/providers/provider-utils.js +13 -20
  273. package/dist/sources/providers/sync-from-ref.js +5 -5
  274. package/dist/sources/providers/tar-utils.js +2 -2
  275. package/dist/sources/providers/website.js +2 -2
  276. package/dist/sources/resolve.js +5 -5
  277. package/dist/sources/website-ingest.js +5 -5
  278. package/dist/storage/database.js +102 -0
  279. package/dist/storage/engines/sqlite-migrations.js +42 -0
  280. package/dist/storage/locations.js +25 -0
  281. package/dist/storage/repositories/index-db.js +43 -0
  282. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  283. package/dist/tasks/backends/cron.js +4 -4
  284. package/dist/tasks/backends/exec-utils.js +32 -0
  285. package/dist/tasks/backends/index.js +3 -3
  286. package/dist/tasks/backends/launchd.js +7 -14
  287. package/dist/tasks/backends/schtasks.js +7 -16
  288. package/dist/tasks/embedded.js +71 -0
  289. package/dist/tasks/parser.js +2 -2
  290. package/dist/tasks/resolveAkmBin.js +1 -1
  291. package/dist/tasks/runner.js +127 -31
  292. package/dist/tasks/schedule.js +1 -1
  293. package/dist/tasks/validator.js +7 -7
  294. package/dist/text-import-hook.mjs +51 -0
  295. package/dist/version.js +2 -1
  296. package/dist/wiki/wiki.js +7 -7
  297. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  298. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  299. package/dist/workflows/cli.js +1 -1
  300. package/dist/workflows/db.js +54 -32
  301. package/dist/workflows/parser.js +4 -4
  302. package/dist/workflows/renderer.js +5 -5
  303. package/dist/workflows/runtime/agent-identity.js +56 -0
  304. package/dist/workflows/runtime/checkin.js +57 -0
  305. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  306. package/dist/workflows/validate-summary.js +82 -0
  307. package/docs/README.md +1 -1
  308. package/docs/data-and-telemetry.md +6 -6
  309. package/package.json +17 -8
  310. package/dist/commands/add-cli.js +0 -279
  311. package/dist/commands/env.js +0 -213
  312. package/dist/integrations/agent/sdk-runner.js +0 -126
  313. package/dist/output/shapes/vault-list.js +0 -19
  314. package/dist/output/text/proposal-producer.js +0 -8
  315. package/dist/output/text/proposal.js +0 -12
  316. package/dist/output/text/vault.js +0 -16
  317. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  318. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  319. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  320. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  321. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  322. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  323. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  324. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -1,19 +1,59 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Staleness-detection pass for `akm improve` (Phase 4A,
6
+ * `.plans/0.8.0/self-improvement-enhancements-plan.md` lines 132-145).
7
+ *
8
+ * Activates the `deprecated` belief-state machinery shipped in Phase 1A
9
+ * (commit 7b6fffe). Without this pass, nothing in the pipeline ever wrote
10
+ * `beliefState: deprecated`, so the -0.15 ranking penalty and the
11
+ * `matchBeliefFilter("historical")` inclusion were dormant.
12
+ *
13
+ * Pipeline
14
+ * --------
15
+ * 1. Walk every memory under `<stash>/memories/` and select candidates
16
+ * whose belief state is NOT already excluded
17
+ * ({contradicted, archived, deprecated}) AND whose `lastConfirmedAt`
18
+ * is absent or older than the configured threshold (default 90 days).
19
+ * Files without `lastConfirmedAt` fall back to file `mtime`.
20
+ * 2. For each candidate, ask the configured validation-tier LLM
21
+ * (`resolveValidationRunner`) whether the candidate is still current
22
+ * given the top-K most-similar memories from the stash.
23
+ * Strict response contract: `YES\nSUPERSEDED_BY: <ref>` or `NO`.
24
+ * Anything else is treated as a parse error and the candidate is skipped.
25
+ * 3. YES → write `beliefState: "deprecated"`, `supersededBy: [<ref>]`,
26
+ * `lastConfirmedAt: <now>`. The supersededBy ref MUST exist in the
27
+ * stash (DB lookup); if it doesn't, treat as NO.
28
+ * NO → write only `lastConfirmedAt: <now>` (refreshes the staleness
29
+ * window). All other frontmatter fields stay untouched.
30
+ *
31
+ * Caching
32
+ * -------
33
+ * Uses the standard `withLlmCache` wrapper with cacheVariant
34
+ * `"staleness_detect"`, so re-running the pass on an unchanged file is a
35
+ * no-op (no LLM call).
36
+ *
37
+ * Feature gate
38
+ * ------------
39
+ * Default OFF. Enable via `features.index.staleness_detection.enabled` (or
40
+ * the boolean shorthand `features.index.staleness_detection = true`).
41
+ * Threshold-days knob lives at
42
+ * `features.index.staleness_detection.options.thresholdDays` (default 90).
43
+ */
4
44
  import { createHash } from "node:crypto";
5
45
  import fs from "node:fs";
6
46
  import path from "node:path";
7
- import { assembleAsset } from "../core/asset-serialize";
8
- import { concurrentMap } from "../core/concurrent";
9
- import { parseFrontmatter, parseFrontmatterBlock } from "../core/frontmatter";
10
- import { warn } from "../core/warn";
11
- import { resolveValidationRunner } from "../integrations/agent/runner";
12
- import { chatCompletion } from "../llm/client";
13
- import { isProcessEnabled } from "../llm/feature-gate";
14
- import { findEntryIdByRef } from "./db";
15
- import { withLlmCache } from "./llm-cache";
16
- import { walkMarkdownFiles } from "./walker";
47
+ import { assembleAsset } from "../../core/asset/asset-serialize.js";
48
+ import { parseFrontmatter, parseFrontmatterBlock } from "../../core/asset/frontmatter.js";
49
+ import { concurrentMap } from "../../core/concurrent.js";
50
+ import { warn } from "../../core/warn.js";
51
+ import { resolveValidationRunner, runnerIsLlm } from "../../integrations/agent/runner.js";
52
+ import { chatCompletion } from "../../llm/client.js";
53
+ import { isProcessEnabled } from "../../llm/feature-gate.js";
54
+ import { findEntryIdByRef } from "../db/db.js";
55
+ import { withLlmCache } from "../db/llm-cache.js";
56
+ import { walkMarkdownFiles } from "../walk/walker.js";
17
57
  /** Frontmatter keys this pass touches. Constants so a future rename only needs to touch one site. */
18
58
  const FM_BELIEF_STATE = "beliefState";
19
59
  const FM_SUPERSEDED_BY = "supersededBy";
@@ -30,7 +70,8 @@ const TOP_K_SIMILAR = 5;
30
70
  * Top-level entry point. Returns a zero-counters result when the feature is
31
71
  * disabled or no validation-tier runner is configured.
32
72
  */
33
- export async function runStalenessDetectionPass(config, sources, signal, db) {
73
+ export async function runStalenessDetectionPass(ctx) {
74
+ const { config, sources, signal, db } = ctx;
34
75
  const start = Date.now();
35
76
  const result = {
36
77
  considered: 0,
@@ -58,7 +99,7 @@ export async function runStalenessDetectionPass(config, sources, signal, db) {
58
99
  result.durationMs = Date.now() - start;
59
100
  return result;
60
101
  }
61
- if (runner.kind !== "llm") {
102
+ if (!runnerIsLlm(runner)) {
62
103
  // MVP scope: only the LLM runner kind is supported. Agent/SDK runners
63
104
  // would require a different prompt-dispatch path that is out of scope
64
105
  // for the initial Phase 4A implementation.
@@ -1,22 +1,34 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Database-backed (SQLite + FTS5/vector) source search implementation.
6
+ *
7
+ * Extracted from source-search.ts to break the circular import:
8
+ * source-search.ts → sources/providers/filesystem.ts → db-search.ts (no cycle)
9
+ *
10
+ * source-search.ts imports this module for the `searchLocal` export.
11
+ * sources/providers/filesystem.ts also imports `searchLocal` from here.
12
+ *
13
+ * Renamed from `local-search.ts` to signal that this is the DB-layer search
14
+ * implementation, not a "local vs. remote" distinction.
15
+ */
4
16
  import fs from "node:fs";
5
- import { buildActionFromContributors, defaultActionContributors } from "../core/action-contributors";
6
- import { makeAssetRef } from "../core/asset-ref";
7
- import { defaultRendererRegistry } from "../core/asset-registry";
8
- import { getDbPath } from "../core/paths";
9
- import { warn } from "../core/warn";
10
- import { getCurrentWorkflowScopeKey } from "../workflows/scope-key";
11
- import { closeDatabase, getAllEntries, getEntryById, getEntryCount, getMeta, getPositiveFeedbackCountsByIds, openExistingDatabase, sanitizeFtsQuery, searchFts, searchVec, } from "./db";
12
- import { ensureIndex } from "./ensure-index";
13
- import { collectGraphRelatedHit, computeGraphBoost, loadGraphBoostContext, } from "./graph-boost";
14
- import { isProposedQuality } from "./metadata";
15
- import { resolveProjectContext } from "./project-context";
16
- import { applyRankingRules, combineSearchScores, normalizeFtsScores } from "./ranking";
17
- import { enrichSearchHit } from "./search-hit-enrichers";
18
- import { buildEditHint, findSourceForPath, isEditable } from "./search-source";
19
- import { deriveSemanticProviderFingerprint, getEffectiveSemanticStatus, isSemanticRuntimeReady, readSemanticStatus, } from "./semantic-status";
17
+ import { buildActionFromContributors, defaultActionContributors } from "../../core/action-contributors.js";
18
+ import { makeAssetRef } from "../../core/asset/asset-ref.js";
19
+ import { defaultRendererRegistry } from "../../core/asset/asset-registry.js";
20
+ import { getDbPath } from "../../core/paths.js";
21
+ import { warn } from "../../core/warn.js";
22
+ import { getCurrentWorkflowScopeKey } from "../../workflows/authoring/scope-key.js";
23
+ import { closeDatabase, getAllEntries, getEntryById, getEntryCount, getMeta, getPositiveFeedbackCountsByIds, openExistingDatabase, sanitizeFtsQuery, searchFts, searchVec, } from "../db/db.js";
24
+ import { ensureIndex } from "../ensure-index.js";
25
+ import { collectGraphRelatedHit, computeGraphBoost, loadGraphBoostContext, } from "../graph/graph-boost.js";
26
+ import { isProposedQuality } from "../passes/metadata.js";
27
+ import { resolveProjectContext } from "../walk/project-context.js";
28
+ import { applyRankingRules, combineSearchScores, normalizeFtsScores } from "./ranking.js";
29
+ import { enrichSearchHit } from "./search-hit-enrichers.js";
30
+ import { buildEditHint, findSourceForPath, isEditable } from "./search-source.js";
31
+ import { deriveSemanticProviderFingerprint, getEffectiveSemanticStatus, isSemanticRuntimeReady, readSemanticStatus, } from "./semantic-status.js";
20
32
  export function buildLocalAction(type, ref, registry = defaultRendererRegistry) {
21
33
  return buildActionFromContributors({ type, ref }, defaultActionContributors(registry)) ?? `akm show ${ref}`;
22
34
  }
@@ -358,7 +370,7 @@ async function tryVecScores(db, query, k, config) {
358
370
  if (hasEmbeddings !== "1")
359
371
  return null;
360
372
  try {
361
- const { embed } = await import("../llm/embedder.js");
373
+ const { embed } = await import("../../llm/embedder.js");
362
374
  const queryEmbedding = await embed(query, config.embedding);
363
375
  const vecResults = searchVec(db, queryEmbedding, k);
364
376
  const scores = new Map();
@@ -1,7 +1,7 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { computeGraphBoost } from "./graph-boost";
4
+ import { computeGraphBoost } from "../graph/graph-boost.js";
5
5
  const TYPE_BOOST = {
6
6
  skill: 0.4,
7
7
  command: 0.35,
@@ -1,8 +1,8 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { getUtilityScoresByIds } from "./db";
5
- import { applyScoreContributors, applyUtilityContributors } from "./ranking-contributors";
4
+ import { getUtilityScoresByIds } from "../db/db.js";
5
+ import { applyScoreContributors, applyUtilityContributors } from "./ranking-contributors.js";
6
6
  export function normalizeFtsScores(results) {
7
7
  const ftsScoreMap = new Map();
8
8
  if (results.length === 0)
@@ -1,9 +1,9 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { makeAssetRef } from "../core/asset-ref";
5
- import { getDerivedForParent } from "./db";
6
- import { getRenderer } from "./file-context";
4
+ import { makeAssetRef } from "../../core/asset/asset-ref.js";
5
+ import { getDerivedForParent } from "../db/db.js";
6
+ import { getRenderer } from "../walk/file-context.js";
7
7
  const rendererSearchHitEnricher = {
8
8
  name: "renderer-search-hit-enricher",
9
9
  appliesTo(ctx) {
@@ -3,15 +3,15 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import { resolveStashDir } from "../core/common";
7
- import { getSources, loadConfig } from "../core/config";
8
- import { resolveSourceProviderFactory } from "../sources/provider-factory";
6
+ import { resolveStashDir } from "../../core/common.js";
7
+ import { getSources, loadConfig } from "../../core/config/config.js";
8
+ import { resolveSourceProviderFactory } from "../../sources/provider-factory.js";
9
9
  // Eager side-effect imports so all built-in source providers self-register
10
10
  // before resolveEntryContentDir() runs.
11
- import "../sources/providers/index";
12
- import { warn } from "../core/warn";
13
- import { ensureGitMirror, getCachePaths, parseGitRepoUrl } from "../sources/providers/git";
14
- import { ensureWebsiteMirror } from "../sources/website-ingest";
11
+ import "../../sources/providers/index.js";
12
+ import { warn } from "../../core/warn.js";
13
+ import { ensureGitMirror, getCachePaths, parseGitRepoUrl } from "../../sources/providers/git.js";
14
+ import { ensureWebsiteMirror } from "../../sources/website-ingest.js";
15
15
  // Legacy "context-hub" / "github" type aliases are normalized to "git" at
16
16
  // config-load time (see src/config.ts), so this set only contains the canonical
17
17
  // type.
@@ -108,7 +108,7 @@ export function resolveSourceEntries(overrideStashDir, existingConfig) {
108
108
  * so the caller can skip it.
109
109
  *
110
110
  * Single source of truth: each provider owns its own path. We instantiate the
111
- * registered {@link import("../sources/provider").SourceProvider} for the entry
111
+ * registered {@link import("../../sources/provider.js").SourceProvider} for the entry
112
112
  * and call `provider.path()`. This replaces the old per-kind switch ladder
113
113
  * (filesystem path / git cache / website cache) that lived here in 0.6.0 —
114
114
  * see spec §10 step 4 and §7 "Removed from 0.6.0".
@@ -2,9 +2,9 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
- import { writeFileAtomic } from "../core/common";
6
- import { getCacheDir, getSemanticStatusPath } from "../core/paths";
7
- import { DEFAULT_LOCAL_MODEL } from "../llm/embedders/local";
5
+ import { writeFileAtomic } from "../../core/common.js";
6
+ import { getCacheDir, getSemanticStatusPath } from "../../core/paths.js";
7
+ import { DEFAULT_LOCAL_MODEL } from "../../llm/embedders/local.js";
8
8
  export function deriveSemanticProviderFingerprint(embedding) {
9
9
  if (embedding?.endpoint) {
10
10
  return `remote:${embedding.endpoint}|${embedding.model}|${embedding.dimension ?? "default"}`;
@@ -0,0 +1,94 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * One-time, read-only guard for un-migrated `vaults/` directories (0.9.0).
6
+ *
7
+ * Background: 0.8.0 introduced the `env` asset type and a `vaults/` → `env/`
8
+ * copy migration (run by `akm-migrate-storage`). 0.9.0 removed the `vault`
9
+ * asset type entirely, and the indexer now unconditionally SKIPS `vaults/`
10
+ * (see `shouldIndexStashFile` in `metadata.ts`). A user who upgrades straight
11
+ * to 0.9.0 without ever running the storage migration therefore has the `.env`
12
+ * data in their `vaults/` directory silently dropped from the index — it was
13
+ * never copied to `env/`, and `vaults/` is no longer scanned.
14
+ *
15
+ * This guard detects exactly that state on a stash and emits ONE clear warning
16
+ * pointing at `akm-migrate-storage`. It is:
17
+ * - Non-destructive: it never reads `.env` contents, never writes, never
18
+ * deletes, and never moves anything. It only stats directory entries.
19
+ * - Idempotent: the warning is emitted at most once per process per stash
20
+ * directory (deduped in-memory).
21
+ *
22
+ * It deliberately does NOT auto-run the copy: filesystem mutation + chmod of
23
+ * secret material stays in the dedicated `akm-migrate-storage` bin, behind the
24
+ * user's explicit invocation, never as a side effect of a normal `akm` command.
25
+ */
26
+ import fs from "node:fs";
27
+ import path from "node:path";
28
+ import { warn } from "../../core/warn.js";
29
+ /**
30
+ * Marker filename the `vaults/` → `env/` migration drops inside `vaults/` after
31
+ * a successful copy. Single source of truth shared with
32
+ * `scripts/migrate-storage.ts` (which writes it) and this guard (which reads
33
+ * it). Its presence means the data already lives under `env/` (or was a no-op
34
+ * fresh install).
35
+ */
36
+ export const MIGRATED_MARKER = ".migrated";
37
+ /** Stashes already warned about in this process — keyed by absolute stash dir. */
38
+ const warnedStashDirs = new Set();
39
+ /** True when `dir` contains at least one `*.env` / `.env` file (recursively). */
40
+ function hasEnvFilesRecursive(dir) {
41
+ let entries;
42
+ try {
43
+ entries = fs.readdirSync(dir, { withFileTypes: true });
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ for (const entry of entries) {
49
+ const full = path.join(dir, entry.name);
50
+ if (entry.isDirectory()) {
51
+ if (hasEnvFilesRecursive(full))
52
+ return true;
53
+ }
54
+ else if (entry.name === ".env" || entry.name.endsWith(".env")) {
55
+ return true;
56
+ }
57
+ }
58
+ return false;
59
+ }
60
+ /**
61
+ * Warn (once) when `<stashDir>/vaults/` holds `.env` data that was never
62
+ * migrated to `env/`. No-op when there is no `vaults/` dir, when the
63
+ * `vaults/.migrated` marker is present, or when `vaults/` has no `.env` files.
64
+ *
65
+ * @returns `true` when a warning was emitted, `false` otherwise. The return is
66
+ * primarily for tests; callers can ignore it.
67
+ */
68
+ export function warnOnUnmigratedVaults(stashDir) {
69
+ const resolved = path.resolve(stashDir);
70
+ if (warnedStashDirs.has(resolved))
71
+ return false;
72
+ const vaultsDir = path.join(resolved, "vaults");
73
+ if (!fs.existsSync(vaultsDir))
74
+ return false;
75
+ // The migration writes this marker after a successful copy. Its presence
76
+ // means the data already lives under env/ (or was a no-op fresh install).
77
+ if (fs.existsSync(path.join(vaultsDir, MIGRATED_MARKER)))
78
+ return false;
79
+ if (!hasEnvFilesRecursive(vaultsDir))
80
+ return false;
81
+ // Mark before emitting so a throw in `warn` can't cause a re-warn loop.
82
+ warnedStashDirs.add(resolved);
83
+ warn(`[akm] WARNING: found un-migrated secrets in ${vaultsDir}.\n` +
84
+ ` The 'vault' asset type was removed in 0.9.0 and 'vaults/' is no longer indexed,\n` +
85
+ ` so this data will NOT appear under 'env:' until you migrate it. Run:\n` +
86
+ ` akm-migrate-storage --yes\n` +
87
+ ` This copies 'vaults/' -> 'env/' (non-destructive — your 'vaults/' dir is left intact).\n` +
88
+ ` See docs/migration/v0.8-to-v0.9.md.`);
89
+ return true;
90
+ }
91
+ /** Test-only: clear the per-process dedup set. */
92
+ export function _resetUnmigratedVaultsGuardForTests() {
93
+ warnedStashDirs.clear();
94
+ }
@@ -54,12 +54,44 @@ export function getUsageEvents(db, filters) {
54
54
  conditions.push("source = ?");
55
55
  params.push(filters.source);
56
56
  }
57
+ if (filters?.since) {
58
+ conditions.push("created_at >= ?");
59
+ params.push(filters.since);
60
+ }
57
61
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
58
62
  const sql = `SELECT id, event_type, query, entry_id, entry_ref, signal, metadata, source, created_at
59
63
  FROM usage_events ${where}
60
64
  ORDER BY id ASC`;
61
65
  return db.prepare(sql).all(...params);
62
66
  }
67
+ /**
68
+ * Aggregate positive/negative feedback counts for a single entry.
69
+ *
70
+ * Lifted verbatim from `akm feedback` (feedback-cli.ts) where the same
71
+ * SUM(CASE …) query was hand-rolled inline. Returns plain numbers (NULL SUMs
72
+ * over an empty set are coalesced to 0) so the result fully materialises before
73
+ * any owning connection closes.
74
+ */
75
+ export function countFeedbackSignals(db, entryId) {
76
+ const counts = db
77
+ .prepare(`SELECT
78
+ SUM(CASE WHEN signal = 'positive' THEN 1 ELSE 0 END) AS pos,
79
+ SUM(CASE WHEN signal = 'negative' THEN 1 ELSE 0 END) AS neg
80
+ FROM usage_events
81
+ WHERE event_type = 'feedback' AND entry_id = ?`)
82
+ .get(entryId);
83
+ return { pos: counts?.pos ?? 0, neg: counts?.neg ?? 0 };
84
+ }
85
+ /**
86
+ * Count usage events of a given `event_type`.
87
+ *
88
+ * Lifted verbatim from `akm improve` (improve.ts) where the show-event count
89
+ * was hand-rolled inline to drive the zero-feedback fallback warning.
90
+ */
91
+ export function countUsageEventsByType(db, eventType) {
92
+ return db.prepare("SELECT COUNT(*) AS cnt FROM usage_events WHERE event_type = ?").get(eventType)
93
+ .cnt;
94
+ }
63
95
  /**
64
96
  * Delete usage events older than the given number of days.
65
97
  */
@@ -9,8 +9,8 @@
9
9
  */
10
10
  import fs from "node:fs";
11
11
  import path from "node:path";
12
- import { toPosix } from "../core/common";
13
- import { parseFrontmatter } from "../core/frontmatter";
12
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
13
+ import { toPosix } from "../../core/common.js";
14
14
  /**
15
15
  * Build a FileContext from a stash root and an absolute file path.
16
16
  *
@@ -71,22 +71,17 @@ export function buildFileContext(stashRoot, absPath) {
71
71
  const matchers = [];
72
72
  /** Renderer lookup by name. */
73
73
  const renderers = new Map();
74
- let builtinsPromise;
75
74
  /**
76
- * Ensure that built-in matchers and renderers are registered.
77
- * Called lazily on first use of runMatchers/getRenderer.
78
- * Stores the in-progress promise so parallel callers don't double-register.
75
+ * Ensure that all built-in indexer contributors are registered.
76
+ *
77
+ * Delegates to the single `initIndexer()` composition root (see
78
+ * `src/indexer/init.ts`). Imported dynamically to keep this a lazy gate and to
79
+ * avoid a static import cycle (init -> renderers -> file-context). Called on
80
+ * first use of runMatchers/getRenderer/getAllRenderers; idempotent.
79
81
  */
80
82
  async function ensureBuiltinsRegistered() {
81
- if (!builtinsPromise) {
82
- builtinsPromise = (async () => {
83
- const { registerBuiltinMatchers } = await import("./matchers.js");
84
- const { registerBuiltinRenderers } = await import("../output/renderers.js");
85
- registerBuiltinMatchers();
86
- registerBuiltinRenderers();
87
- })();
88
- }
89
- return builtinsPromise;
83
+ const { initIndexer } = await import("../init.js");
84
+ await initIndexer();
90
85
  }
91
86
  /**
92
87
  * Register an AssetMatcher.
@@ -8,10 +8,10 @@
8
8
  * one heuristic. The public `*Matcher` exports compose those facts into the
9
9
  * `MatchResult` shape expected by the rest of the indexer.
10
10
  */
11
- import { defaultRendererRegistry } from "../core/asset-registry";
12
- import { SCRIPT_EXTENSIONS } from "../core/asset-spec";
13
- import { looksLikeWorkflow } from "../workflows/parser";
14
- import { registerMatcher } from "./file-context";
11
+ import { defaultRendererRegistry } from "../../core/asset/asset-registry.js";
12
+ import { SCRIPT_EXTENSIONS } from "../../core/asset/asset-spec.js";
13
+ import { looksLikeWorkflow } from "../../workflows/parser.js";
14
+ import { registerMatcher } from "./file-context.js";
15
15
  // ---------------------------------------------------------------------------
16
16
  // Private data
17
17
  // ---------------------------------------------------------------------------
@@ -56,11 +56,6 @@ const DIR_TYPE_MAP = [
56
56
  type: "env",
57
57
  test: (_, fileName) => fileName === ".env" || fileName.endsWith(".env"),
58
58
  },
59
- {
60
- dir: "vaults",
61
- type: "vault",
62
- test: (_, fileName) => fileName === ".env" || fileName.endsWith(".env"),
63
- },
64
59
  {
65
60
  dir: "secrets",
66
61
  type: "secret",
@@ -74,6 +69,15 @@ const DIR_TYPE_MAP = [
74
69
  type: "task",
75
70
  test: (ext) => ext === ".md",
76
71
  },
72
+ {
73
+ // #561 — agent session assets live under `sessions/<harness>/<id>.md`.
74
+ // classifyByDirectory walks every ancestor dir, so a nested file still
75
+ // matches the `sessions` rule. Without this entry the file falls through
76
+ // to classifyBySmartMd and is mistyped as `knowledge`.
77
+ dir: "sessions",
78
+ type: "session",
79
+ test: (ext) => ext === ".md",
80
+ },
77
81
  ];
78
82
  const COMMAND_PLACEHOLDER_RE = /\$ARGUMENTS|\$[123]\b/;
79
83
  // Files that should never be treated as the typed asset for the surrounding
@@ -3,12 +3,12 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import { parseAssetRef } from "../core/asset-ref";
7
- import { resolveAssetPathFromName, TYPE_DIRS } from "../core/asset-spec";
8
- import { isWithin } from "../core/common";
9
- import { resolveSourcesForOrigin } from "../registry/origin-resolve";
10
- import { lookup } from "./indexer";
11
- import { resolveSourceEntries } from "./search-source";
6
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
7
+ import { resolveAssetPathFromName, TYPE_DIRS } from "../../core/asset/asset-spec.js";
8
+ import { isWithin } from "../../core/common.js";
9
+ import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
10
+ import { lookup } from "../indexer.js";
11
+ import { resolveSourceEntries } from "../search/search-source.js";
12
12
  function normalizeRef(ref) {
13
13
  return typeof ref === "string" ? parseAssetRef(ref) : ref;
14
14
  }
@@ -20,7 +20,7 @@
20
20
  import fs from "node:fs";
21
21
  import os from "node:os";
22
22
  import path from "node:path";
23
- import { resolveWorkflowScopeAnchor } from "../workflows/scope-key.js";
23
+ import { resolveWorkflowScopeAnchor } from "../../workflows/authoring/scope-key.js";
24
24
  // Words that appear in almost every project name and carry no discriminating
25
25
  // signal for ranking. Filtered out after token splitting.
26
26
  const TOKEN_BLOCKLIST = new Set([
@@ -10,8 +10,9 @@
10
10
  */
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
- import { isRelevantAssetFile } from "../core/asset-spec";
14
- import { buildFileContext } from "./file-context";
13
+ import { isRelevantAssetFile } from "../../core/asset/asset-spec.js";
14
+ import { spawnSync } from "../../runtime.js";
15
+ import { buildFileContext } from "./file-context.js";
15
16
  const SKIP_DIRS = new Set([".git", "node_modules", "bin", ".cache"]);
16
17
  /**
17
18
  * Walk a type root directory and return files grouped by their parent directory.
@@ -80,7 +81,7 @@ function walkStashGit(stashRoot) {
80
81
  if (!isInsideGitRepo(stashRoot))
81
82
  return null;
82
83
  // Get tracked + untracked (non-ignored) files
83
- const result = Bun.spawnSync(["git", "ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", "."], {
84
+ const result = spawnSync(["git", "ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", "."], {
84
85
  cwd: stashRoot,
85
86
  });
86
87
  // result.success is false if the process exited non-zero OR git was not found
@@ -0,0 +1,39 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Shared agent-command-builder types and helpers (#563).
6
+ *
7
+ * Extracted from `agent/builders.ts` so per-harness builders (e.g.
8
+ * `harnesses/claude/agent-builder.ts`) can depend on the common
9
+ * types/validation WITHOUT creating an import cycle back through
10
+ * `builders.ts` (which imports the per-harness builders into its registry).
11
+ * This module is a dependency-graph LEAF for the builder subsystem.
12
+ *
13
+ * Behaviour-preserving: the type shapes and helper bodies are unchanged from
14
+ * their previous home in `builders.ts`.
15
+ */
16
+ import { UsageError } from "../../core/errors.js";
17
+ /**
18
+ * Guard against values that start with `--`, which would be mis-interpreted as
19
+ * CLI flags by the spawned process when used as flag values (model, systemPrompt).
20
+ * Bun.spawn uses array argv so there is no shell injection, but a `--`-prefixed
21
+ * value passed as the argument to `--model` or `--system-prompt` can still
22
+ * confuse the CLI parser of the target process.
23
+ */
24
+ export function assertNotFlag(value, field) {
25
+ if (value?.trimStart().startsWith("--")) {
26
+ throw new UsageError(`${field} must not start with "--": ${JSON.stringify(value.slice(0, 60))}`, "INVALID_FLAG_VALUE");
27
+ }
28
+ }
29
+ /**
30
+ * Normalize a toolPolicy value to a comma-separated string suitable for a
31
+ * CLI flag. Structured policy objects are JSON-serialized.
32
+ */
33
+ export function normalizeTools(tools) {
34
+ if (typeof tools === "string")
35
+ return tools;
36
+ if (Array.isArray(tools))
37
+ return tools.join(",");
38
+ return JSON.stringify(tools);
39
+ }