akm-cli 0.8.1 → 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 (318) hide show
  1. package/CHANGELOG.md +258 -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/stash-skeleton/README.md +76 -0
  9. package/dist/assets/tasks/core/backup.yml +4 -0
  10. package/dist/assets/tasks/core/extract.yml +4 -0
  11. package/dist/assets/tasks/core/improve.yml +4 -0
  12. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  13. package/dist/assets/tasks/core/sync.yml +4 -0
  14. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  15. package/dist/assets/tasks/core/version-check.yml +4 -0
  16. package/dist/cli/config-migrate.js +6 -6
  17. package/dist/cli/config-validate.js +4 -4
  18. package/dist/cli/confirm.js +3 -3
  19. package/dist/cli/parse-args.js +1 -1
  20. package/dist/cli/shared.js +51 -14
  21. package/dist/cli-node.mjs +26 -0
  22. package/dist/cli.js +171 -3857
  23. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  24. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  25. package/dist/commands/agent/contribute-cli.js +200 -0
  26. package/dist/commands/completions.js +1 -1
  27. package/dist/commands/config-cli.js +240 -3
  28. package/dist/commands/config-edit.js +344 -0
  29. package/dist/commands/db-cli.js +2 -2
  30. package/dist/commands/env/env-cli.js +529 -0
  31. package/dist/commands/env/env.js +410 -0
  32. package/dist/commands/env/secret-cli.js +259 -0
  33. package/dist/commands/{secret.js → env/secret.js} +6 -47
  34. package/dist/commands/events.js +4 -4
  35. package/dist/commands/feedback-cli.js +18 -34
  36. package/dist/commands/graph/graph-cli.js +132 -0
  37. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  38. package/dist/commands/health/checks.js +279 -0
  39. package/dist/commands/health.js +101 -249
  40. package/dist/commands/{consolidate.js → improve/consolidate.js} +52 -40
  41. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  42. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  43. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  44. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  45. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  46. package/dist/commands/{extract.js → improve/extract.js} +185 -26
  47. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +4 -4
  48. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +45 -23
  49. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  50. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +10 -5
  51. package/dist/commands/{improve.js → improve/improve.js} +536 -248
  52. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  53. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  54. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  55. package/dist/commands/{reflect.js → improve/reflect.js} +33 -28
  56. package/dist/commands/improve/session-asset.js +248 -0
  57. package/dist/commands/lint/agent-linter.js +1 -1
  58. package/dist/commands/lint/base-linter.js +55 -37
  59. package/dist/commands/lint/command-linter.js +1 -1
  60. package/dist/commands/lint/default-linter.js +1 -1
  61. package/dist/commands/lint/env-key-rules.js +1 -1
  62. package/dist/commands/lint/index.js +19 -25
  63. package/dist/commands/lint/knowledge-linter.js +1 -1
  64. package/dist/commands/lint/memory-linter.js +1 -1
  65. package/dist/commands/lint/registry.js +8 -8
  66. package/dist/commands/lint/skill-linter.js +1 -1
  67. package/dist/commands/lint/task-linter.js +1 -1
  68. package/dist/commands/lint/workflow-linter.js +1 -1
  69. package/dist/commands/lint.js +1 -1
  70. package/dist/commands/observability-cli.js +244 -0
  71. package/dist/commands/{proposal-drain-policies.js → proposal/drain-policies.js} +3 -3
  72. package/dist/commands/{proposal-drain.js → proposal/drain.js} +15 -10
  73. package/dist/commands/proposal/proposal-cli.js +478 -0
  74. package/dist/commands/{proposal.js → proposal/proposal.js} +5 -5
  75. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  76. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  77. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  78. package/dist/{core → commands/proposal/validators}/proposals.js +13 -7
  79. package/dist/commands/{curate.js → read/curate.js} +7 -7
  80. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  81. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  82. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  83. package/dist/commands/read/search-cli.js +207 -0
  84. package/dist/commands/{search.js → read/search.js} +22 -27
  85. package/dist/commands/{show.js → read/show.js} +77 -44
  86. package/dist/commands/registry-cli.js +8 -8
  87. package/dist/commands/remember.js +8 -8
  88. package/dist/commands/sources/add-cli.js +293 -0
  89. package/dist/commands/{history.js → sources/history.js} +27 -25
  90. package/dist/commands/{info.js → sources/info.js} +6 -6
  91. package/dist/commands/{init.js → sources/init.js} +10 -5
  92. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  93. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  94. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  95. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  96. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  97. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  98. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  99. package/dist/commands/sources/sources-cli.js +305 -0
  100. package/dist/commands/sources/stash-cli.js +219 -0
  101. package/dist/commands/sources/stash-skeleton.js +79 -0
  102. package/dist/commands/tasks/default-tasks.js +173 -0
  103. package/dist/commands/tasks/tasks-cli.js +210 -0
  104. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  105. package/dist/commands/wiki-cli.js +307 -0
  106. package/dist/commands/workflow-cli.js +329 -0
  107. package/dist/core/action-contributors.js +1 -1
  108. package/dist/core/assert.js +40 -0
  109. package/dist/core/asset/asset-create.js +54 -0
  110. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  111. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  112. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  113. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  114. package/dist/core/asset/stash-meta.js +110 -0
  115. package/dist/core/best-effort.js +64 -0
  116. package/dist/core/common.js +32 -18
  117. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  118. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  119. package/dist/core/{config-schema.js → config/config-schema.js} +45 -1
  120. package/dist/core/config/config-types.js +16 -0
  121. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  122. package/dist/core/{config.js → config/config.js} +10 -8
  123. package/dist/core/env-secret-ref.js +90 -0
  124. package/dist/core/errors.js +13 -3
  125. package/dist/core/events.js +27 -4
  126. package/dist/core/file-lock.js +1 -1
  127. package/dist/core/improve-types.js +48 -0
  128. package/dist/core/lesson-lint.js +2 -2
  129. package/dist/core/paths.js +2 -2
  130. package/dist/{setup/ripgrep-install.js → core/ripgrep/install.js} +2 -2
  131. package/dist/{setup/ripgrep-resolve.js → core/ripgrep/resolve.js} +2 -2
  132. package/dist/core/state-db.js +88 -46
  133. package/dist/core/text-truncation.js +148 -0
  134. package/dist/core/time.js +1 -1
  135. package/dist/core/write-source.js +98 -85
  136. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  137. package/dist/indexer/{db.js → db/db.js} +126 -116
  138. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  139. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  140. package/dist/indexer/ensure-index.js +4 -4
  141. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  142. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  143. package/dist/indexer/indexer.js +37 -30
  144. package/dist/indexer/init.js +54 -0
  145. package/dist/indexer/manifest.js +10 -10
  146. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +92 -23
  147. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  148. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  149. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  150. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  151. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  152. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  153. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  154. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  155. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  156. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  157. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  158. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  159. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  160. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  161. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  162. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  163. package/dist/integrations/agent/builder-shared.js +39 -0
  164. package/dist/integrations/agent/builders.js +14 -81
  165. package/dist/integrations/agent/config.js +6 -4
  166. package/dist/integrations/agent/detect.js +1 -1
  167. package/dist/integrations/agent/index.js +23 -8
  168. package/dist/integrations/agent/prompts.js +2 -3
  169. package/dist/integrations/agent/runner.js +22 -3
  170. package/dist/integrations/agent/spawn.js +9 -10
  171. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  172. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  173. package/dist/integrations/harnesses/claude/index.js +64 -0
  174. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +16 -1
  175. package/dist/integrations/harnesses/index.js +144 -0
  176. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  177. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  178. package/dist/integrations/harnesses/opencode/index.js +59 -0
  179. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  180. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  181. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  182. package/dist/integrations/harnesses/types.js +43 -0
  183. package/dist/integrations/lockfile.js +7 -16
  184. package/dist/integrations/session-logs/index.js +82 -9
  185. package/dist/llm/call-ai.js +4 -4
  186. package/dist/llm/client.js +131 -6
  187. package/dist/llm/embedder.js +6 -6
  188. package/dist/llm/embedders/local.js +9 -22
  189. package/dist/llm/embedders/remote.js +2 -2
  190. package/dist/llm/embedders/types.js +1 -1
  191. package/dist/llm/graph-extract.js +31 -12
  192. package/dist/llm/index-passes.js +1 -1
  193. package/dist/llm/memory-infer.js +12 -5
  194. package/dist/llm/metadata-enhance.js +2 -2
  195. package/dist/output/context.js +6 -44
  196. package/dist/output/renderers.js +88 -58
  197. package/dist/output/shapes/curate.js +7 -3
  198. package/dist/output/shapes/distill.js +7 -3
  199. package/dist/output/shapes/env-list.js +18 -16
  200. package/dist/output/shapes/events.js +5 -4
  201. package/dist/output/shapes/helpers.js +2 -4
  202. package/dist/output/shapes/history.js +7 -3
  203. package/dist/output/shapes/passthrough.js +8 -11
  204. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  205. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  206. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  207. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  208. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  209. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  210. package/dist/output/shapes/registry-search.js +7 -3
  211. package/dist/output/shapes/registry.js +12 -0
  212. package/dist/output/shapes/search.js +7 -3
  213. package/dist/output/shapes/secret-list.js +18 -16
  214. package/dist/output/shapes/show.js +7 -3
  215. package/dist/output/shapes.js +55 -30
  216. package/dist/output/text/add.js +2 -3
  217. package/dist/output/text/clone.js +2 -3
  218. package/dist/output/text/config.js +2 -3
  219. package/dist/output/text/curate.js +4 -3
  220. package/dist/output/text/distill.js +2 -3
  221. package/dist/output/text/enable-disable.js +5 -4
  222. package/dist/output/text/env.js +13 -0
  223. package/dist/output/text/events.js +5 -4
  224. package/dist/output/text/feedback.js +4 -3
  225. package/dist/output/text/helpers.js +54 -39
  226. package/dist/output/text/history.js +2 -3
  227. package/dist/output/text/import.js +2 -3
  228. package/dist/output/text/index.js +2 -3
  229. package/dist/output/text/info.js +2 -3
  230. package/dist/output/text/init.js +2 -3
  231. package/dist/output/text/list.js +2 -3
  232. package/dist/output/text/proposal/producer.js +9 -0
  233. package/dist/output/text/proposal/proposal.js +13 -0
  234. package/dist/output/text/registry-commands.js +8 -7
  235. package/dist/output/text/registry.js +12 -0
  236. package/dist/output/text/remember.js +4 -3
  237. package/dist/output/text/remove.js +2 -3
  238. package/dist/output/text/save.js +2 -3
  239. package/dist/output/text/search.js +4 -3
  240. package/dist/output/text/show.js +4 -3
  241. package/dist/output/text/update.js +2 -3
  242. package/dist/output/text/upgrade.js +2 -3
  243. package/dist/output/text/wiki.js +12 -11
  244. package/dist/output/text/workflow.js +12 -10
  245. package/dist/output/text.js +66 -32
  246. package/dist/registry/build-index.js +11 -10
  247. package/dist/registry/factory.js +1 -1
  248. package/dist/registry/origin-resolve.js +1 -1
  249. package/dist/registry/providers/index.js +2 -2
  250. package/dist/registry/providers/skills-sh.js +91 -72
  251. package/dist/registry/providers/static-index.js +75 -52
  252. package/dist/registry/resolve.js +3 -3
  253. package/dist/runtime.js +242 -0
  254. package/dist/scripts/migrate-storage.js +1594 -673
  255. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +240 -166
  256. package/dist/setup/detect.js +338 -9
  257. package/dist/setup/harness-config-import.js +56 -0
  258. package/dist/setup/registry-stash-loader.js +99 -0
  259. package/dist/setup/setup.js +664 -96
  260. package/dist/sources/include.js +1 -1
  261. package/dist/sources/provider-factory.js +2 -2
  262. package/dist/sources/providers/filesystem.js +3 -3
  263. package/dist/sources/providers/git.js +9 -9
  264. package/dist/sources/providers/index.js +4 -4
  265. package/dist/sources/providers/npm.js +6 -6
  266. package/dist/sources/providers/provider-utils.js +13 -20
  267. package/dist/sources/providers/sync-from-ref.js +5 -5
  268. package/dist/sources/providers/tar-utils.js +2 -2
  269. package/dist/sources/providers/website.js +2 -2
  270. package/dist/sources/resolve.js +5 -5
  271. package/dist/sources/website-ingest.js +5 -5
  272. package/dist/storage/database.js +102 -0
  273. package/dist/storage/engines/sqlite-migrations.js +42 -0
  274. package/dist/storage/locations.js +25 -0
  275. package/dist/storage/repositories/index-db.js +43 -0
  276. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  277. package/dist/tasks/backends/cron.js +4 -4
  278. package/dist/tasks/backends/exec-utils.js +32 -0
  279. package/dist/tasks/backends/index.js +3 -3
  280. package/dist/tasks/backends/launchd.js +7 -14
  281. package/dist/tasks/backends/schtasks.js +7 -16
  282. package/dist/tasks/embedded.js +71 -0
  283. package/dist/tasks/parser.js +2 -2
  284. package/dist/tasks/resolveAkmBin.js +1 -1
  285. package/dist/tasks/runner.js +28 -15
  286. package/dist/tasks/schedule.js +1 -1
  287. package/dist/tasks/validator.js +7 -7
  288. package/dist/text-import-hook.mjs +51 -0
  289. package/dist/version.js +2 -1
  290. package/dist/wiki/wiki.js +7 -7
  291. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  292. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  293. package/dist/workflows/cli.js +1 -1
  294. package/dist/workflows/db.js +50 -32
  295. package/dist/workflows/parser.js +4 -4
  296. package/dist/workflows/renderer.js +5 -5
  297. package/dist/workflows/runtime/agent-identity.js +56 -0
  298. package/dist/workflows/runtime/checkin.js +57 -0
  299. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  300. package/dist/workflows/validate-summary.js +82 -0
  301. package/docs/README.md +1 -1
  302. package/docs/data-and-telemetry.md +6 -6
  303. package/package.json +16 -8
  304. package/dist/commands/add-cli.js +0 -279
  305. package/dist/commands/env.js +0 -213
  306. package/dist/integrations/agent/sdk-runner.js +0 -126
  307. package/dist/output/shapes/vault-list.js +0 -19
  308. package/dist/output/text/proposal-producer.js +0 -8
  309. package/dist/output/text/proposal.js +0 -12
  310. package/dist/output/text/vault.js +0 -16
  311. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  312. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  313. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  314. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  315. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  316. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  317. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  318. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -3,20 +3,20 @@
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 { SCRIPT_EXTENSIONS } from "../core/asset-spec";
7
- import { isHttpUrl, resolveStashDir, toErrorMessage } from "../core/common";
8
- import { concurrentMap } from "../core/concurrent";
9
- import { getDbPath } from "../core/paths";
10
- import { isVerbose, warn, warnVerbose } from "../core/warn";
11
- import { resolveIndexPassLLM } from "../llm/index-passes";
12
- import { takeWorkflowDocument } from "../workflows/document-cache";
13
- import { clearStaleCacheEntries, closeDatabase, deleteEntriesByDir, deleteEntriesByIds, deleteEntriesByStashDir, deleteIndexDirStatesByStashDir, getAllEntriesForEmbedding, getEmbeddingCount, getEntriesByDir, getEntryCount, getIndexDirState, getMeta, isVecAvailable, openDatabase, openExistingDatabase, rebuildFts, relinkUsageEvents, setMeta, upsertEmbedding, upsertEntry, upsertIndexDirState, upsertUtilityScore, upsertWorkflowDocument, warnIfVecMissing, } from "./db";
14
- import { deleteStoredGraph } from "./graph-db";
15
- import { applyCuratedFrontmatter, applyWikiFrontmatter, generateMetadataFlat, isEnrichmentComplete, isWorkflowSkipWarning, loadStashFile, shouldIndexStashFile, } from "./metadata";
16
- import { buildSearchText } from "./search-fields";
17
- import { classifySemanticFailure, clearSemanticStatus, deriveSemanticProviderFingerprint, writeSemanticStatus, } from "./semantic-status";
18
- import { ensureUsageEventsSchema, purgeOldUsageEvents } from "./usage-events";
19
- import { walkStashFlat } from "./walker";
6
+ import { SCRIPT_EXTENSIONS } from "../core/asset/asset-spec.js";
7
+ import { isHttpUrl, resolveStashDir, toErrorMessage } from "../core/common.js";
8
+ import { concurrentMap } from "../core/concurrent.js";
9
+ import { getDbPath } from "../core/paths.js";
10
+ import { isVerbose, warn, warnVerbose } from "../core/warn.js";
11
+ import { resolveIndexPassLLM } from "../llm/index-passes.js";
12
+ import { takeWorkflowDocument } from "../workflows/runtime/document-cache.js";
13
+ import { clearStaleCacheEntries, closeDatabase, deleteEntriesByDir, deleteEntriesByIds, deleteEntriesByStashDir, deleteIndexDirStatesByStashDir, getAllEntriesForEmbedding, getEmbeddableEntryCount, getEmbeddingCount, getEntriesByDir, getEntryCount, getIndexDirState, getMeta, isVecAvailable, openDatabase, openExistingDatabase, rebuildFts, relinkUsageEvents, setMeta, upsertEmbedding, upsertEntry, upsertIndexDirState, upsertUtilityScore, upsertWorkflowDocument, warnIfVecMissing, } from "./db/db.js";
14
+ import { deleteStoredGraph } from "./db/graph-db.js";
15
+ import { applyCuratedFrontmatter, applyWikiFrontmatter, generateMetadataFlat, isEnrichmentComplete, isWorkflowSkipWarning, loadStashFile, shouldIndexStashFile, } from "./passes/metadata.js";
16
+ import { buildSearchText } from "./search/search-fields.js";
17
+ import { classifySemanticFailure, clearSemanticStatus, deriveSemanticProviderFingerprint, writeSemanticStatus, } from "./search/semantic-status.js";
18
+ import { ensureUsageEventsSchema, purgeOldUsageEvents } from "./usage/usage-events.js";
19
+ import { walkStashFlat } from "./walk/walker.js";
20
20
  function throwIfAborted(signal) {
21
21
  if (signal?.aborted) {
22
22
  throw signal.reason instanceof Error ? signal.reason : new Error("index interrupted");
@@ -177,7 +177,8 @@ async function runFinalizePhase(ctx) {
177
177
  setMeta(db, "hasEmbeddings", embeddingResult.success ? "1" : "0");
178
178
  warnIfVecMissing(db);
179
179
  const totalEntries = getEntryCount(db);
180
- const verification = verifyIndexState(db, config, totalEntries, embeddingResult);
180
+ const semanticEntryCount = getEmbeddableEntryCount(db);
181
+ const verification = verifyIndexState(db, config, semanticEntryCount, embeddingResult);
181
182
  if (config.semanticSearchMode === "off") {
182
183
  clearSemanticStatus();
183
184
  }
@@ -232,11 +233,17 @@ export async function akmIndex(options) {
232
233
  const clean = options?.clean === true;
233
234
  const dryRun = options?.dryRun === true;
234
235
  // Load config and resolve all stash sources
235
- const { loadConfig } = await import("../core/config.js");
236
+ const { loadConfig } = await import("../core/config/config.js");
236
237
  const config = loadConfig();
238
+ // One-time, read-only guard: warn if the writable stash still holds an
239
+ // un-migrated `vaults/` directory. In 0.9.0 the indexer skips `vaults/`
240
+ // entirely, so an unmigrated vault's `.env` data would silently never be
241
+ // indexed. Non-destructive — only stats, never reads/writes/deletes.
242
+ const { warnOnUnmigratedVaults } = await import("./usage/unmigrated-vaults-guard.js");
243
+ warnOnUnmigratedVaults(stashDir);
237
244
  // Ensure git stash caches are extracted before resolving stash dirs,
238
245
  // so their content directories exist on disk for the walker to discover.
239
- const { ensureSourceCaches, resolveSourceEntries } = await import("./search-source.js");
246
+ const { ensureSourceCaches, resolveSourceEntries } = await import("./search/search-source.js");
240
247
  await ensureSourceCaches(config, { force: full });
241
248
  const allSourceEntries = resolveSourceEntries(stashDir, config);
242
249
  const allSourceDirs = allSourceEntries.map((s) => s.path);
@@ -995,11 +1002,11 @@ function getSemanticSearchLabel(semanticSearchMode, embeddingProvider, vecAvaila
995
1002
  return "disabled";
996
1003
  return `${embeddingProvider} embeddings, ${vecAvailable ? "sqlite-vec" : "JS fallback"}`;
997
1004
  }
998
- function verifyIndexState(db, config, totalEntries, embeddingResult) {
1005
+ function verifyIndexState(db, config, embeddableEntries, embeddingResult) {
999
1006
  const embeddingCount = getEmbeddingCount(db);
1000
1007
  const vecAvailable = isVecAvailable(db);
1001
1008
  const embeddingProvider = getEmbeddingProvider(config.embedding);
1002
- if (totalEntries === 0) {
1009
+ if (embeddableEntries === 0) {
1003
1010
  return {
1004
1011
  ok: true,
1005
1012
  message: "Index ready. No assets were found yet.",
@@ -1007,7 +1014,7 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
1007
1014
  semanticSearchMode: config.semanticSearchMode,
1008
1015
  semanticStatus: config.semanticSearchMode === "off" ? "disabled" : "pending",
1009
1016
  embeddingProvider,
1010
- entryCount: totalEntries,
1017
+ entryCount: embeddableEntries,
1011
1018
  embeddingCount,
1012
1019
  vecAvailable,
1013
1020
  };
@@ -1020,20 +1027,20 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
1020
1027
  semanticSearchMode: config.semanticSearchMode,
1021
1028
  semanticStatus: "disabled",
1022
1029
  embeddingProvider,
1023
- entryCount: totalEntries,
1030
+ entryCount: embeddableEntries,
1024
1031
  embeddingCount,
1025
1032
  vecAvailable,
1026
1033
  };
1027
1034
  }
1028
- if (embeddingCount >= totalEntries) {
1035
+ if (embeddingCount >= embeddableEntries) {
1029
1036
  return {
1030
1037
  ok: true,
1031
- message: `Semantic search ready (${embeddingCount}/${totalEntries} embeddings, ${vecAvailable ? "sqlite-vec active" : "JS fallback active"}).`,
1038
+ message: `Semantic search ready (${embeddingCount}/${embeddableEntries} embeddings, ${vecAvailable ? "sqlite-vec active" : "JS fallback active"}).`,
1032
1039
  semanticSearchEnabled: true,
1033
1040
  semanticSearchMode: config.semanticSearchMode,
1034
1041
  semanticStatus: vecAvailable ? "ready-vec" : "ready-js",
1035
1042
  embeddingProvider,
1036
- entryCount: totalEntries,
1043
+ entryCount: embeddableEntries,
1037
1044
  embeddingCount,
1038
1045
  vecAvailable,
1039
1046
  };
@@ -1041,7 +1048,7 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
1041
1048
  return {
1042
1049
  ok: false,
1043
1050
  message: embeddingResult.message ??
1044
- `Semantic search verification failed (${embeddingCount}/${totalEntries} embeddings available).`,
1051
+ `Semantic search verification failed (${embeddingCount}/${embeddableEntries} embeddings available).`,
1045
1052
  guidance: embeddingProvider === "remote"
1046
1053
  ? "Check your embedding endpoint and credentials, then retry `akm index --full --verbose`."
1047
1054
  : "Retry `akm index --full --verbose`. If it still fails, confirm local model downloads are permitted and see docs/configuration.md for local embedding dependency setup.",
@@ -1049,7 +1056,7 @@ function verifyIndexState(db, config, totalEntries, embeddingResult) {
1049
1056
  semanticSearchMode: config.semanticSearchMode,
1050
1057
  semanticStatus: "blocked",
1051
1058
  embeddingProvider,
1052
- entryCount: totalEntries,
1059
+ entryCount: embeddableEntries,
1053
1060
  embeddingCount,
1054
1061
  vecAvailable,
1055
1062
  };
@@ -1075,8 +1082,8 @@ function resolveIndexedFiles(dirPath, files, stash) {
1075
1082
  return resolved.size > 0 ? [...resolved] : files;
1076
1083
  }
1077
1084
  async function enhanceStashWithLlm(llmConfig, stash, files, summary, signal, db, entryKeys, reEnrich, akmConfig, onEntryDone) {
1078
- const { enhanceMetadata } = await import("../llm/metadata-enhance");
1079
- const { computeBodyHash, getLlmCacheEntry, upsertLlmCacheEntry } = await import("./db.js");
1085
+ const { enhanceMetadata } = await import("../llm/metadata-enhance.js");
1086
+ const { computeBodyHash, getLlmCacheEntry, upsertLlmCacheEntry } = await import("./db/db.js");
1080
1087
  const results = await concurrentMap(stash.entries, async (entry, idx) => {
1081
1088
  if (signal?.aborted)
1082
1089
  return entry;
@@ -1233,8 +1240,8 @@ function mergeLegacyEntry(entry, legacyEntries) {
1233
1240
  * `NotFoundError` with their own messaging.
1234
1241
  */
1235
1242
  export async function lookup(ref) {
1236
- const { loadConfig } = await import("../core/config.js");
1237
- const { resolveSourceEntries } = await import("./search-source.js");
1243
+ const { loadConfig } = await import("../core/config/config.js");
1244
+ const { resolveSourceEntries } = await import("./search/search-source.js");
1238
1245
  const config = loadConfig();
1239
1246
  const sources = resolveSourceEntries(undefined, config);
1240
1247
  if (sources.length === 0)
@@ -0,0 +1,54 @@
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
+ * Explicit composition root for the indexer's built-in registrations.
6
+ *
7
+ * Historically two independent lazy gates (`ensureBuiltinsRegistered` in
8
+ * `walk/file-context.ts` and `ensureBuiltinMetadataContributorsRegistered` in
9
+ * `passes/metadata-contributors.ts`) each registered a different built-in set
10
+ * on first use. That implicit, order-dependent wiring is the M1/M2 finding in
11
+ * `docs/technical/code-health-brittleness-audit.md`.
12
+ *
13
+ * `initIndexer()` folds both into a single deterministic, idempotent entry
14
+ * point. It registers, exactly once:
15
+ *
16
+ * 1. Built-in matchers — `registerBuiltinMatchers()` (`walk/matchers.ts`).
17
+ * 2. Built-in renderers — `registerBuiltinRenderers()` (`output/renderers.ts`).
18
+ * 3. Metadata contributors — top-level registration side-effects that run when
19
+ * `output/renderers.ts` and `workflows/renderer.ts` are imported.
20
+ *
21
+ * Importing `output/renderers.ts` satisfies both (2) and the renderer-owned
22
+ * metadata contributors; `workflows/renderer.ts` is imported explicitly for the
23
+ * workflow contributor (it is already transitively pulled in by renderers, but
24
+ * the explicit import preserves the original gate's import set and keeps the
25
+ * wiring self-documenting).
26
+ *
27
+ * Timing is preserved: this stays a *lazy* gate. It is awaited from the same
28
+ * accessor call sites the old gates were awaited from, so no startup work is
29
+ * forced eagerly. The shared promise makes concurrent and repeat calls safe —
30
+ * the registrations run at most once per process.
31
+ */
32
+ let initPromise;
33
+ /**
34
+ * Idempotently register every built-in indexer contributor (matchers,
35
+ * renderers, and metadata contributors).
36
+ *
37
+ * Safe to call repeatedly and concurrently: the registration work runs at most
38
+ * once; subsequent calls await the same resolved promise.
39
+ */
40
+ export function initIndexer() {
41
+ if (!initPromise) {
42
+ initPromise = (async () => {
43
+ const { registerBuiltinMatchers } = await import("./walk/matchers.js");
44
+ // Importing renderers registers the built-in metadata contributors as a
45
+ // load-time side-effect and exposes registerBuiltinRenderers().
46
+ const { registerBuiltinRenderers } = await import("../output/renderers.js");
47
+ // Imported for the workflow metadata contributor's load-time side-effect.
48
+ await import("../workflows/renderer.js");
49
+ registerBuiltinMatchers();
50
+ registerBuiltinRenderers();
51
+ })();
52
+ }
53
+ return initPromise;
54
+ }
@@ -11,16 +11,16 @@
11
11
  */
12
12
  import fs from "node:fs";
13
13
  import path from "node:path";
14
- import { makeAssetRef } from "../core/asset-ref";
15
- import { deriveCanonicalAssetNameFromStashRoot } from "../core/asset-spec";
16
- import { resolveStashDir } from "../core/common";
17
- import { loadConfig } from "../core/config";
18
- import { getDbPath } from "../core/paths";
19
- import { warn } from "../core/warn";
20
- import { closeDatabase, getAllEntries, getEntryCount, getMeta, openExistingDatabase } from "./db";
21
- import { generateMetadataFlat, loadStashFile } from "./metadata";
22
- import { resolveSourceEntries } from "./search-source";
23
- import { walkStashFlat } from "./walker";
14
+ import { makeAssetRef } from "../core/asset/asset-ref.js";
15
+ import { deriveCanonicalAssetNameFromStashRoot } from "../core/asset/asset-spec.js";
16
+ import { resolveStashDir } from "../core/common.js";
17
+ import { loadConfig } from "../core/config/config.js";
18
+ import { getDbPath } from "../core/paths.js";
19
+ import { warn } from "../core/warn.js";
20
+ import { closeDatabase, getAllEntries, getEntryCount, getMeta, openExistingDatabase } from "./db/db.js";
21
+ import { generateMetadataFlat, loadStashFile } from "./passes/metadata.js";
22
+ import { resolveSourceEntries } from "./search/search-source.js";
23
+ import { walkStashFlat } from "./walk/walker.js";
24
24
  const MAX_DESCRIPTION_LENGTH = 80;
25
25
  /**
26
26
  * Truncate a description string to a maximum length, appending "..." if truncated.
@@ -1,19 +1,52 @@
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
+ * Memory inference pass for `akm index` (#201).
6
+ *
7
+ * Detects memories pending inference, asks the configured LLM to compress each
8
+ * into one higher-signal derived memory, and writes the result back as a new
9
+ * memory file with frontmatter `inferred: true` + a `source:` backref to the
10
+ * parent memory.
11
+ *
12
+ * Pending predicate (see {@link isPendingMemory}):
13
+ * - File lives under `<stashRoot>/memories/` and ends in `.md`.
14
+ * - Frontmatter does NOT have `inferenceProcessed: true` (parent already split).
15
+ * - Frontmatter does NOT have `inferred: true` (this is itself a child fact).
16
+ *
17
+ * Idempotency: after a successful split the parent's frontmatter is rewritten
18
+ * with `inferenceProcessed: true`. A subsequent `akm index` therefore skips
19
+ * the parent without re-running the LLM.
20
+ *
21
+ * Disabling — two orthogonal gates:
22
+ * 1. `profiles.improve.default.processes.memoryInference.enabled = false`
23
+ * blocks the pass at the feature-flag layer (no network call may ever
24
+ * issue). Historically the v1 spec §14 gate, superseded by the 0.8.0
25
+ * profile shape.
26
+ * 2. `index.memory.llm = false` (or no resolvable LLM profile) opts the
27
+ * pass out at the per-pass layer (#208).
28
+ * A pass runs iff both layers allow it. Existing inferred children are
29
+ * NEVER deleted — the user keeps what was already produced.
30
+ *
31
+ * Locked v1 contract:
32
+ * - LLM access is exclusively via `resolveIndexPassLLM("memory", config)`.
33
+ * - All child memory writes go through `writeAssetToSource` in
34
+ * `src/core/write-source.ts`. The parent's frontmatter rewrite is an
35
+ * explicit narrow exception — see {@link markParentProcessed}.
36
+ */
4
37
  import fs from "node:fs";
5
38
  import path from "node:path";
6
- import { parseAssetRef } from "../core/asset-ref";
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 { writeAssetToSource } from "../core/write-source";
12
- import { isProcessEnabled } from "../llm/feature-gate";
13
- import { resolveIndexPassLLM } from "../llm/index-passes";
14
- import * as memoryInfer from "../llm/memory-infer";
15
- import { withLlmCache } from "./llm-cache";
16
- import { walkMarkdownFiles } from "./walker";
39
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
40
+ import { assembleAsset } from "../../core/asset/asset-serialize.js";
41
+ import { parseFrontmatter, parseFrontmatterBlock } from "../../core/asset/frontmatter.js";
42
+ import { concurrentMap } from "../../core/concurrent.js";
43
+ import { warn } from "../../core/warn.js";
44
+ import { writeAssetToSource } from "../../core/write-source.js";
45
+ import { isProcessEnabled } from "../../llm/feature-gate.js";
46
+ import { resolveIndexPassLLM } from "../../llm/index-passes.js";
47
+ import * as memoryInfer from "../../llm/memory-infer.js";
48
+ import { withLlmCache } from "../db/llm-cache.js";
49
+ import { walkMarkdownFiles } from "../walk/walker.js";
17
50
  /**
18
51
  * Frontmatter keys this pass cares about. Constants so a future rename only
19
52
  * needs to touch one site.
@@ -37,17 +70,24 @@ const FM_CAPTURE_MODE = "captureMode";
37
70
  * Both must allow the call for the pass to run. Either set to `false`
38
71
  * short-circuits to a no-op result.
39
72
  */
40
- export async function runMemoryInferencePass(config, sources, signal, db, reEnrich, onProgress, options = {}) {
73
+ export async function runMemoryInferencePass(ctx) {
74
+ const { config, sources, signal, db, reEnrich, onProgress, options = {} } = ctx;
41
75
  const result = {
42
76
  considered: 0,
43
77
  cacheHits: 0,
78
+ retryAttempts: 0,
44
79
  splitParents: 0,
45
80
  writtenFacts: 0,
46
81
  skippedNoFacts: 0,
47
82
  skippedChildExists: 0,
48
83
  skippedAborted: 0,
49
84
  unaccounted: 0,
85
+ htmlErrorCount: 0,
50
86
  };
87
+ // Mutable sink threaded into compressMemoryToDerivedMemory so the per-call
88
+ // HTML-error categorization (which is otherwise swallowed inside the feature
89
+ // gate) bubbles up into the pass result.
90
+ const inferTelemetry = {};
51
91
  // Gate 1 — feature gate via isProcessEnabled, which reads the 0.8.0 path
52
92
  // (profiles.improve.default.processes.memoryInference.enabled). Defaults to
53
93
  // enabled when the key is absent.
@@ -103,31 +143,51 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
103
143
  // the hit count separately so the operational yield rate
104
144
  // (writtenFacts / freshAttempts) is interpretable as the cache warms.
105
145
  let fromCache = false;
146
+ // Count single bounded retries for transient LLM failures on this
147
+ // candidate. Bumped via the `onRetryAttempt` callback threaded into
148
+ // `chatCompletion`; surfaced as `retryAttempts` telemetry, never as a
149
+ // failure for the same call.
150
+ let retryAttempts = 0;
151
+ const onRetryAttempt = () => {
152
+ retryAttempts += 1;
153
+ };
106
154
  const derived = db
107
155
  ? await withLlmCache(db, record.filePath, record.body, reEnrich ?? false, () => memoryInfer.compressMemoryToDerivedMemory(llmConfig, record.body, signal, config, (evt) => {
108
156
  warn(`[akm] LLM fallback for ${evt.feature}: ${evt.reason}`);
109
- }), validate, undefined, "", {
157
+ }, inferTelemetry, onRetryAttempt), validate, undefined, "", {
110
158
  onCacheHit: () => {
111
159
  fromCache = true;
112
160
  },
113
161
  })
114
162
  : await memoryInfer.compressMemoryToDerivedMemory(llmConfig, record.body, signal, config, (evt) => {
115
163
  warn(`[akm] LLM fallback for ${evt.feature}: ${evt.reason}`);
116
- });
164
+ }, inferTelemetry, onRetryAttempt);
117
165
  if (!derived) {
118
- return { skipped: true, fromCache };
166
+ return { skipped: true, fromCache, retryAttempts };
119
167
  }
120
- const written = await writeDerivedMemory(record, derived);
121
- if (written > 0) {
168
+ const writeOutcome = await writeDerivedMemory(record, derived);
169
+ if (writeOutcome.written > 0) {
122
170
  markParentProcessed(record);
123
- return { skipped: false, splitParent: true, written, fromCache };
171
+ return { skipped: false, splitParent: true, written: writeOutcome.written, fromCache, retryAttempts };
124
172
  }
125
173
  // LLM produced a valid derived draft but no file was written — either
126
174
  // because `<parent>.derived.md` already exists on disk or
127
175
  // `writeAssetToSource` threw. Categorise as `childExists` so the
128
176
  // attempt is accounted for in health metrics rather than vanishing
129
177
  // into the freshAttempts denominator.
130
- return { skipped: false, splitParent: false, written: 0, fromCache, childExists: true };
178
+ //
179
+ // When the child already exists on disk the inference is, by definition,
180
+ // already complete — so mark the parent processed here too (#550).
181
+ // Without this, `isPendingMemory()` re-queues the same parent every run
182
+ // (the `written > 0` path was previously the only site that marks it),
183
+ // causing permanent re-queueing and wasted LLM calls. A genuine write
184
+ // *failure* (`writeAssetToSource` threw) must NOT mark the parent — it
185
+ // should be retried next run — so we key off the explicit `childExists`
186
+ // outcome rather than the conflated `written === 0`.
187
+ if (writeOutcome.childExists) {
188
+ markParentProcessed(record);
189
+ }
190
+ return { skipped: false, splitParent: false, written: 0, fromCache, retryAttempts, childExists: true };
131
191
  },
132
192
  // Default concurrency of 4 for cloud APIs. Set `llm.concurrency: 1`
133
193
  // in config.json for local model servers (LM Studio, Ollama).
@@ -151,6 +211,9 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
151
211
  if (res.fromCache) {
152
212
  result.cacheHits += 1;
153
213
  }
214
+ if ("retryAttempts" in res) {
215
+ result.retryAttempts += res.retryAttempts;
216
+ }
154
217
  if (res.skipped) {
155
218
  result.skippedNoFacts += 1;
156
219
  // Intentionally NOT marked processed — a transient LLM failure should
@@ -183,6 +246,7 @@ export async function runMemoryInferencePass(config, sources, signal, db, reEnri
183
246
  currentRef: pending[i]?.ref,
184
247
  });
185
248
  }
249
+ result.htmlErrorCount = inferTelemetry.htmlErrorCount ?? 0;
186
250
  return result;
187
251
  }
188
252
  // ── Pending detection ───────────────────────────────────────────────────────
@@ -260,7 +324,6 @@ function toMemoryName(memoriesDir, filePath) {
260
324
  // user has organised under memories/.
261
325
  return rel.replace(/\\/g, "/").replace(/\.md$/i, "");
262
326
  }
263
- // ── Writing derived memories + marking parent ───────────────────────────────
264
327
  async function writeDerivedMemory(parent, derived) {
265
328
  const writeTarget = {
266
329
  kind: "filesystem",
@@ -277,17 +340,23 @@ async function writeDerivedMemory(parent, derived) {
277
340
  const childRefStr = `memory:${childName}`;
278
341
  const childPath = path.join(parent.stashRoot, "memories", `${childName}.md`);
279
342
  if (fs.existsSync(childPath)) {
280
- return 0;
343
+ // The derived child is already on disk — inference for this parent is
344
+ // complete. Report `childExists` so the caller marks the parent processed
345
+ // (#550) instead of re-queueing it forever.
346
+ return { written: 0, childExists: true };
281
347
  }
282
348
  try {
283
349
  const content = renderDerivedMemory(parent, derived);
284
350
  const childRef = parseAssetRef(childRefStr);
285
351
  await writeAssetToSource(writeTarget, writeConfig, childRef, content);
286
- return 1;
352
+ return { written: 1, childExists: false };
287
353
  }
288
354
  catch (err) {
289
355
  warn(`memory inference: failed to write derived memory ${childName}: ${err instanceof Error ? err.message : String(err)}`);
290
- return 0;
356
+ // A genuine write failure — the parent must remain pending so it is
357
+ // retried on the next run. `childExists: false` keeps it from being
358
+ // marked processed.
359
+ return { written: 0, childExists: false };
291
360
  }
292
361
  }
293
362
  function renderDerivedMemory(parent, derived) {
@@ -2,15 +2,17 @@
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
  const contributors = [];
5
- let builtinsPromise;
5
+ /**
6
+ * Ensure that all built-in indexer contributors are registered.
7
+ *
8
+ * Delegates to the single `initIndexer()` composition root (see
9
+ * `src/indexer/init.ts`). Imported dynamically to keep this a lazy gate and to
10
+ * avoid a static import cycle (init -> renderers -> metadata-contributors).
11
+ * Called on first use of getMetadataContributors; idempotent.
12
+ */
6
13
  async function ensureBuiltinMetadataContributorsRegistered() {
7
- if (!builtinsPromise) {
8
- builtinsPromise = (async () => {
9
- await import("../output/renderers.js");
10
- await import("../workflows/renderer.js");
11
- })();
12
- }
13
- return builtinsPromise;
14
+ const { initIndexer } = await import("../init.js");
15
+ await initIndexer();
14
16
  }
15
17
  export function registerMetadataContributor(contributor) {
16
18
  contributors.push(contributor);
@@ -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 { deriveCanonicalAssetName, deriveCanonicalAssetNameFromStashRoot, isRelevantAssetFile, } from "../core/asset-spec";
7
- import { asNonEmptyString, isAssetType, writeFileAtomic } from "../core/common";
8
- import { parseFrontmatter } from "../core/frontmatter";
9
- import { isVerbose, warn } from "../core/warn";
10
- import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "./file-context";
11
- import { applyMetadataContributors } from "./metadata-contributors";
6
+ import { deriveCanonicalAssetName, deriveCanonicalAssetNameFromStashRoot, isRelevantAssetFile, } from "../../core/asset/asset-spec.js";
7
+ import { parseFrontmatter } from "../../core/asset/frontmatter.js";
8
+ import { asNonEmptyString, isAssetType, writeFileAtomic } from "../../core/common.js";
9
+ import { isVerbose, warn } from "../../core/warn.js";
10
+ import { buildFileContext, buildRenderContext, getRenderer, runMatchers } from "../walk/file-context.js";
11
+ import { applyMetadataContributors } from "./metadata-contributors.js";
12
12
  export const SCOPE_KEYS = ["user", "agent", "run", "channel"];
13
13
  // ── Load / Write ────────────────────────────────────────────────────────────
14
14
  const STASH_FILENAME = ".stash.json";
@@ -480,18 +480,15 @@ export function shouldIndexStashFile(stashRoot, file, options) {
480
480
  const segments = relPath.split(/[\\/]+/).filter(Boolean);
481
481
  if (segments.length === 0)
482
482
  return true;
483
- // Skip env / vault .env files that have a sibling .sensitive marker file.
484
- if ((segments[0] === "env" || segments[0] === "vaults") &&
485
- (file.endsWith(".env") || path.basename(file) === ".env")) {
483
+ // Skip env .env files that have a sibling .sensitive marker file.
484
+ if (segments[0] === "env" && (file.endsWith(".env") || path.basename(file) === ".env")) {
486
485
  const markerPath = file.replace(/\.env$/, ".sensitive");
487
486
  if (fs.existsSync(markerPath))
488
487
  return false;
489
488
  }
490
- // Deprecation: once a stash has migrated to the `env/` directory, the legacy
491
- // `vaults/` copy is frozen. Skip indexing it so the same keys are not
492
- // double-surfaced under both `vault:` and `env:`. (Pre-migration stashes
493
- // with no `env/` dir still index `vaults/` normally.)
494
- if (segments[0] === "vaults" && fs.existsSync(path.join(stashRoot, "env"))) {
489
+ // The legacy `vaults/` directory (frozen copy left by the 0.8 migration) is
490
+ // never indexed the `vault` asset type was removed in 0.9.0.
491
+ if (segments[0] === "vaults") {
495
492
  return false;
496
493
  }
497
494
  // Skip secret files that are themselves a `.sensitive` marker, or that have a
@@ -853,11 +850,10 @@ async function buildEntryFromFile(file, assetType, canonicalName, dirPath, pkgMe
853
850
  }
854
851
  }
855
852
  // Extract @param from script files.
856
- // Env / vault files (.env) and secret files (whole-file secrets) are
857
- // deliberately excluded — their contents are secrets and must never be
858
- // parsed for @param or any other metadata that could embed a value into the
859
- // entry.
860
- if (ext !== ".md" && assetType !== "env" && assetType !== "vault" && assetType !== "secret") {
853
+ // Env files (.env) and secret files (whole-file secrets) are deliberately
854
+ // excluded — their contents are secrets and must never be parsed for @param
855
+ // or any other metadata that could embed a value into the entry.
856
+ if (ext !== ".md" && assetType !== "env" && assetType !== "secret") {
861
857
  const content = ctx.content();
862
858
  const scriptParams = extractScriptParameters(file, content);
863
859
  if (scriptParams)
@@ -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.