akm-cli 0.9.0-rc.8 → 0.9.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 (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -1,98 +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 fs from "node:fs";
5
- import { conceptIdFromTypeName } from "../../core/asset/resolve-ref.js";
6
- import { acquireMaintenanceActivitySync } from "../../core/maintenance-barrier.js";
7
- import { getStateDbPath } from "../../core/state-db.js";
8
- import { openDatabase } from "../../storage/database.js";
9
4
  import { getUtilityScoresByIds } from "../../storage/repositories/index-utility-repository.js";
10
5
  import { applyBeliefStateScoreCeiling, applyContributorAblation, applyScoreContributors, applyUtilityContributors, defaultRankingContributors, defaultUtilityRankingContributors, } from "./ranking-contributors.js";
11
- /**
12
- * R2 — best-effort load of `asset_salience.rank_score` from state.db for the
13
- * ranked items. Fail-open: any error (state.db locked by a concurrent improve
14
- * run, missing table, unreadable path) returns an empty map, which makes the
15
- * salience contributor a no-op — byte-identical to pre-R2 ranking.
16
- *
17
- * Deliberately NOT `openStateDatabase()`: that helper runs migrations and sets
18
- * a 30 s busy timeout — too heavy for a search hot path. This opens read-only,
19
- * never creates or migrates state.db (missing file / missing table = empty
20
- * map), and caps lock waits at 250 ms so a concurrent improve run can only
21
- * ever cost the search a quarter second, not a stall.
22
- */
23
- export function loadSalienceRankScores(items) {
24
- const result = new Map();
25
- if (items.length === 0)
26
- return result;
27
- try {
28
- const dbPath = getStateDbPath();
29
- if (!fs.existsSync(dbPath))
30
- return result; // improve loop has never run here
31
- const releaseActivity = acquireMaintenanceActivitySync("state-db");
32
- // Fold both durable salience spellings into the single `IN` query, keyed
33
- // back to the entry id (Chunk-8 WI-8.5c — the legacy `type:name` arm is
34
- // retired):
35
- // • the fully-qualified `item_ref` (`<bundle>//<conceptId>`) — what the
36
- // improve writer keys salience by when the planner resolved provenance;
37
- // • the bare conceptId — the write-key fallback for entries with no
38
- // resolved `item_ref` (`item_ref` NULL is the bare form of the same key).
39
- // Output is keyed by id, so a fully-qualified match wins over the bare-conceptId
40
- // match for the same asset id.
41
- const idByRef = new Map();
42
- try {
43
- for (const item of items) {
44
- // Bare-conceptId arm (the item_ref-absent write-key fallback).
45
- idByRef.set(conceptIdFromTypeName(item.entry.type, item.entry.name), { id: item.id, isNew: false });
46
- // Fully-qualified `item_ref` arm (skipped for NULL-provenance rows).
47
- if (item.itemRef)
48
- idByRef.set(item.itemRef, { id: item.id, isNew: true });
49
- }
50
- const stateDb = openDatabase(dbPath, { readonly: true });
51
- try {
52
- try {
53
- stateDb.exec("PRAGMA busy_timeout = 250");
54
- }
55
- catch {
56
- // pragma failure on a readonly handle is fine — default timeout applies
57
- }
58
- const refs = [...idByRef.keys()];
59
- const CHUNK = 500;
60
- const newHits = new Set();
61
- for (let i = 0; i < refs.length; i += CHUNK) {
62
- const chunk = refs.slice(i, i + CHUNK);
63
- const placeholders = chunk.map(() => "?").join(",");
64
- const rows = stateDb
65
- .prepare(`SELECT asset_ref, rank_score FROM asset_salience WHERE asset_ref IN (${placeholders})`)
66
- .all(...chunk);
67
- for (const row of rows) {
68
- const target = idByRef.get(row.asset_ref);
69
- if (!target)
70
- continue;
71
- // New-grammar match wins over a stale legacy row for the same id;
72
- // a legacy match applies only when no new row has claimed the id.
73
- if (target.isNew) {
74
- result.set(target.id, row.rank_score);
75
- newHits.add(target.id);
76
- }
77
- else if (!newHits.has(target.id)) {
78
- result.set(target.id, row.rank_score);
79
- }
80
- }
81
- }
82
- }
83
- finally {
84
- stateDb.close();
85
- }
86
- }
87
- finally {
88
- releaseActivity();
89
- }
90
- }
91
- catch {
92
- // Fail open — search must never break because state.db is unavailable.
93
- }
94
- return result;
95
- }
96
6
  export function normalizeFtsScores(results) {
97
7
  const ftsScoreMap = new Map();
98
8
  if (results.length === 0)
@@ -124,6 +34,8 @@ export function combineSearchScores(options) {
124
34
  score: combinedScore,
125
35
  rankingMode: embedScore !== undefined ? "hybrid" : "fts",
126
36
  itemRef: result.itemRef,
37
+ bundleId: result.bundleId,
38
+ conceptId: result.conceptId,
127
39
  });
128
40
  }
129
41
  for (const [id, cosine] of options.embedScoreMap) {
@@ -144,6 +56,8 @@ export function combineSearchScores(options) {
144
56
  score: cosine * VEC_WEIGHT,
145
57
  rankingMode: "semantic",
146
58
  itemRef: found.itemRef,
59
+ bundleId: found.bundleId,
60
+ conceptId: found.conceptId,
147
61
  });
148
62
  }
149
63
  return scored;
@@ -159,21 +73,26 @@ export function applyRankingRules(options) {
159
73
  graphContext: options.graphContext,
160
74
  projectContext: options.projectContext,
161
75
  };
162
- // Eval/debug only: AKM_ABLATE_CONTRIBUTORS lets the ablation harness drop
163
- // named contributors to measure their effect. Resolved once per query;
164
- // a no-op (full lists) when the env var is unset — see applyContributorAblation.
165
- const ablateEnv = process.env.AKM_ABLATE_CONTRIBUTORS;
76
+ // Eval/debug only: lets the ablation harness drop named contributors to
77
+ // measure their effect. Resolved once per query; a no-op (full lists) when
78
+ // unset — see applyContributorAblation. C9: DI via
79
+ // `options.ablateContributors` is now the primary path (see the field's
80
+ // doc comment on RankEntriesOptions); AKM_ABLATE_CONTRIBUTORS is a
81
+ // temporary fallback for the one caller that cannot yet thread the option
82
+ // through (see that doc comment for why).
83
+ const ablateEnv = options.ablateContributors ?? process.env.AKM_ABLATE_CONTRIBUTORS;
166
84
  const activeScoreContributors = applyContributorAblation(defaultRankingContributors, ablateEnv);
167
85
  const activeUtilityContributors = applyContributorAblation(defaultUtilityRankingContributors, ablateEnv);
168
86
  for (const item of options.items) {
169
87
  applyScoreContributors(item, rankingContext, activeScoreContributors);
170
88
  }
171
89
  const { global: utilScoresMap, scoped: scopedUtilScoresMap } = getUtilityScoresByIds(options.db, options.items.map((item) => item.id), options.scopeKey);
172
- // R2 — compose the improve loop's salience into user-facing ranking.
173
- // undefined = load from state.db (default); null = explicitly disabled.
174
- const salienceRankScores = options.salienceRankScores === null
175
- ? new Map()
176
- : (options.salienceRankScores ?? loadSalienceRankScores(options.items));
90
+ // R2 / #692 — salience-ranking is not in defaultUtilityRankingContributors
91
+ // (see ranking-contributors.ts), so this is never consumed by the default
92
+ // ranking path below; it exists only for a caller that explicitly builds a
93
+ // contributor list including salienceRankingContributor. undefined/null
94
+ // both normalize to "no data" — there is no state.db fallback load.
95
+ const salienceRankScores = options.salienceRankScores ?? new Map();
177
96
  const utilityContext = {
178
97
  ...rankingContext,
179
98
  utilityScores: utilScoresMap,
@@ -17,7 +17,8 @@
17
17
  // scored via FTS against it. Changing what buildSearchFields includes shifts
18
18
  // the detector's recall baseline for ALL existing canary sets — coordinate
19
19
  // with src/commands/improve/collapse-detector.ts (buildCanaryQuery) and expect
20
- // operators to re-mint via `akm improve canary --refresh` after such a change.
20
+ // operators to re-mint via `bun scripts/refresh-canary-set.ts --refresh` after
21
+ // such a change.
21
22
  export function buildSearchFields(entry) {
22
23
  const name = entry.name.replace(/[-_]/g, " ").toLowerCase();
23
24
  const description = (entry.description ?? "").toLowerCase();
@@ -28,6 +29,8 @@ export function buildSearchFields(entry) {
28
29
  tagParts.push(entry.aliases.join(" "));
29
30
  const tags = tagParts.join(" ").toLowerCase();
30
31
  const hintParts = [];
32
+ if (entry.hints)
33
+ hintParts.push(entry.hints.join(" "));
31
34
  if (entry.searchHints)
32
35
  hintParts.push(entry.searchHints.join(" "));
33
36
  if (entry.examples)
@@ -50,6 +53,8 @@ export function buildSearchFields(entry) {
50
53
  hintParts.push(entry.whenToUse);
51
54
  const hints = hintParts.join(" ").toLowerCase();
52
55
  const contentParts = [];
56
+ if (entry.content)
57
+ contentParts.push(entry.content);
53
58
  if (entry.toc) {
54
59
  contentParts.push(entry.toc.map((h) => h.text).join(" "));
55
60
  }
@@ -74,7 +79,7 @@ export function buildSearchFields(entry) {
74
79
  }
75
80
  /**
76
81
  * Build a single concatenated search text string for an entry.
77
- * Used for the `search_text` column in the entries table (backward compat)
82
+ * Used for the `search_text` column in the entries table.
78
83
  * and for generating embedding text.
79
84
  */
80
85
  export function buildSearchText(entry) {
@@ -4,85 +4,101 @@
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { isSourceWriteActivated } from "../../core/activation-policy.js";
7
- import { displayRef } from "../../core/asset/resolve-ref.js";
8
- import { resolveStashDir } from "../../core/common.js";
9
- import { bundlesToSourceEntries, getSources, loadConfig } from "../../core/config/config.js";
10
- import { resolveGitContentRoot } from "../../core/write-source.js";
11
- import { lockContentRootFor, readLockfile } from "../../integrations/lockfile.js";
7
+ import { isWithin, resolveStashDir } from "../../core/common.js";
8
+ import { bundleComponentConfig, bundlesToSourceEntries, getSources, loadConfig } from "../../core/config/config.js";
9
+ import { resolveGitContentRoot, resolveWritable } from "../../core/write-source.js";
10
+ import { lockContentRootFor } from "../../integrations/lockfile.js";
12
11
  import { resolveSourceProviderFactory } from "../../sources/provider-factory.js";
13
12
  // Eager side-effect imports so all built-in source providers self-register
14
13
  // before resolveEntryContentDir() runs.
15
14
  import "../../sources/providers/index.js";
16
15
  import { warn } from "../../core/warn.js";
17
- // Legacy "context-hub" / "github" type aliases are normalized to "git" at
18
- // config-load time (see src/config.ts), so this set only contains the canonical
19
- // type.
20
- const GIT_STASH_TYPES = new Set(["git"]);
21
16
  // ── Resolution ──────────────────────────────────────────────────────────────
22
17
  /**
23
18
  * Build the ordered list of stash sources, walking every configured stash
24
19
  * once. Iteration order:
25
20
  *
26
- * 1. The primary stash directory (the entry marked `primary: true`, or the
27
- * legacy top-level `stashDir`). Always emitted, even when the directory
28
- * does not yet exist on disk, so callers can use it as the clone target.
29
- * 2. Each entry in `config.sources[]` (in declared order), excluding the
30
- * one already emitted as the primary.
31
- * 3. Each entry in `config.installed[]` (registry-managed stashes).
21
+ * 1. An explicit argument or `AKM_BUNDLE_DIR`, when present.
22
+ * 2. The configured `defaultBundle`, after component-root validation.
23
+ * 3. Remaining configured bundles in installation-priority order.
32
24
  *
33
25
  * Replaces the previous four-pass loop that walked `stashes[]` separately
34
- * for each provider kind. Disabled entries (`enabled: false`) and entries
35
- * whose disk path doesn't exist are filtered after deduplication.
26
+ * for each provider kind. Disabled entries (`enabled: false`) are filtered
27
+ * after deduplication. Missing configured roots remain in the result so the
28
+ * indexer can classify their scan as incomplete instead of mistaking them for
29
+ * removed sources.
36
30
  */
37
31
  export function resolveSourceEntries(overrideStashDir, existingConfig) {
38
- const stashDir = overrideStashDir ?? resolveStashDir();
39
32
  const config = existingConfig ?? loadConfig();
40
- // Primary stash is always writable.
41
- const sources = [{ path: stashDir, writable: true }];
42
- const seen = new Set([path.resolve(stashDir)]);
43
- const addSource = (dir, registryId, writable) => {
33
+ const configuredEntries = bundlesToSourceEntries(config) ?? [];
34
+ const envOverride = process.env.AKM_BUNDLE_DIR?.trim();
35
+ const implicitStashDir = overrideStashDir !== undefined
36
+ ? path.resolve(overrideStashDir)
37
+ : envOverride
38
+ ? resolveStashDir()
39
+ : config.defaultBundle
40
+ ? undefined
41
+ : resolveStashDir();
42
+ // Explicit and environment overrides stay first. Without either override,
43
+ // the configured default enters through the validated loop below.
44
+ const sources = implicitStashDir ? [{ path: implicitStashDir, writable: true }] : [];
45
+ const seen = new Set(implicitStashDir ? [implicitStashDir] : []);
46
+ const addSource = (dir, registryId, writable, type, adapterId, unresolved = false) => {
44
47
  const resolved = path.resolve(dir);
45
48
  if (seen.has(resolved)) {
46
49
  // Already in the source list — typically the primary stash injected at
47
50
  // sources[0] before this loop. Enrich that entry with whatever metadata
48
- // the matching config source carries so `--source <config-name>` can
51
+ // the matching config source carries so `--from <config-name>` can
49
52
  // find it via registryId. Without this, the primary stash entry stays
50
53
  // identity-less and a user-named primary source ("name": "my-stash")
51
54
  // would validate but match zero entries when filtering.
52
55
  const existing = sources.find((s) => s.path === resolved);
53
- if (existing) {
54
- if (registryId && !existing.registryId)
56
+ if (existing && existing.type === undefined) {
57
+ if (registryId)
55
58
  existing.registryId = registryId;
56
- if (writable && !existing.writable)
57
- existing.writable = true;
59
+ existing.type = type;
60
+ existing.writable = writable;
61
+ existing.adapterId = adapterId;
58
62
  }
63
+ if (existing && unresolved)
64
+ existing.unresolved = true;
59
65
  return;
60
66
  }
61
67
  seen.add(resolved);
62
68
  if (isSuspiciousStashRoot(dir)) {
63
69
  warn(`Warning: stash root "${dir}" appears to be a system directory. This may be unintentional.`);
64
70
  }
65
- if (isValidDirectory(dir)) {
66
- sources.push({
67
- path: resolved,
68
- ...(registryId ? { registryId } : {}),
69
- ...(writable ? { writable: true } : {}),
70
- });
71
- }
71
+ sources.push({
72
+ path: resolved,
73
+ ...(registryId ? { registryId } : {}),
74
+ writable,
75
+ type,
76
+ ...(adapterId ? { adapterId } : {}),
77
+ ...(unresolved ? { unresolved: true } : {}),
78
+ });
72
79
  };
73
80
  // 0.9.0 shape (spec §10.1 / D-R5): resolve from `bundles` + `defaultBundle`.
74
- // `bundlesToSourceEntries` returns the source list ordered defaultBundle-first
75
- // (already injected as the primary via `resolveStashDir` above), then map
76
- // insertion order — folding the retired sources[]/installed[] roles into one
77
- // list. Each entry's `name` is its bundle key, so the addSource `registryId`
78
- // == the bundle id. A config with no bundles yields just the primary stash.
79
- for (const entry of bundlesToSourceEntries(config) ?? []) {
81
+ // `bundlesToSourceEntries` returns the configured default first, then map
82
+ // insertion order. Each entry is validated before insertion so a component
83
+ // root can never escape its provider's materialized content root.
84
+ for (const entry of configuredEntries) {
80
85
  if (entry.enabled === false)
81
86
  continue;
82
- const dir = resolveEntryContentDir(entry);
83
- if (dir == null)
87
+ const component = bundleComponentConfig(config.bundles?.[entry.name ?? ""]);
88
+ const contentRoot = resolveEntryContentDir(entry);
89
+ if (contentRoot == null) {
90
+ const unresolvedPath = path.join(implicitStashDir ?? process.cwd(), ".akm", "unresolved-sources", entry.name ?? entry.type);
91
+ addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
92
+ continue;
93
+ }
94
+ const dir = path.resolve(contentRoot, component?.root ?? ".");
95
+ if (!isWithin(dir, contentRoot)) {
96
+ warn(`Warning: component root "${component?.root}" escapes bundle "${entry.name}"; skipping source.`);
97
+ const unresolvedPath = path.join(contentRoot, ".akm", "unresolved-sources", entry.name ?? entry.type);
98
+ addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
84
99
  continue;
85
- addSource(dir, entry.name, entry.writable === true);
100
+ }
101
+ addSource(dir, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter);
86
102
  }
87
103
  return sources;
88
104
  }
@@ -138,7 +154,7 @@ export function resolveEntryContentDir(entry) {
138
154
  // layout puts indexable files under `<repo>/content/`, so the walker needs
139
155
  // that subdirectory. This is a content-layout convention, not a provider
140
156
  // capability — keep it here.
141
- if (GIT_STASH_TYPES.has(entry.type)) {
157
+ if (entry.type === "git") {
142
158
  return resolveGitContentRoot(dir);
143
159
  }
144
160
  return dir;
@@ -151,11 +167,6 @@ export function resolveAllStashDirs(overrideStashDir) {
151
167
  }
152
168
  /**
153
169
  * Return the resolved absolute paths of all writable stash sources.
154
- *
155
- * The primary stash is always writable. Filesystem/git sources that have
156
- * `writable: true` in config are also included. Registry-cached sources
157
- * (installed without `writable: true`) are excluded because they are
158
- * overwritten on `akm update` and must never be mutated.
159
170
  */
160
171
  export function getWritableStashDirs(overrideStashDir, existingConfig) {
161
172
  return resolveSourceEntries(overrideStashDir, existingConfig)
@@ -194,46 +205,22 @@ export function getPrimarySource(sources) {
194
205
  }
195
206
  // ── Editability ─────────────────────────────────────────────────────────────
196
207
  /**
197
- * Determine whether a file is safe to edit in place.
198
- *
199
- * 0.9.0 (spec §10.2 / Decision D): the files that are NOT editable are those
200
- * under a bundle's materialized cache root (the lock's `localRoot`) whose bundle
201
- * is not explicitly `writable` — `akm update` overwrites them without warning.
202
- * The read-only decision is re-expressed via bundle `writable` + lock `localRoot`
203
- * (replacing the retired `installed[].cacheDir` scan); a writable git/filesystem
204
- * bundle stays editable, and a source with no lock entry (a plain filesystem
205
- * bundle / local project dir) is the user's domain to manage.
208
+ * Determine whether AKM policy allows modifying this exact file in place.
209
+ * Ownership is resolved by longest source-root match and unknown ownership
210
+ * fails closed. Resolved sources already carry canonical `resolveWritable()`
211
+ * semantics; editability is never persisted in the index.
206
212
  */
207
- export function isEditable(filePath, config) {
208
- const cfg = config ?? loadConfig();
209
- const resolved = path.resolve(filePath);
210
- const isWin = process.platform === "win32";
211
- const bundles = cfg.bundles ?? {};
212
- const startsWithin = (root) => {
213
- const base = path.resolve(root);
214
- return isWin
215
- ? resolved.toLowerCase().startsWith(base.toLowerCase() + path.sep)
216
- : resolved.startsWith(base + path.sep);
217
- };
218
- for (const lock of readLockfile()) {
219
- if (!lock.localRoot)
220
- continue;
221
- // The lock is keyed by bundle id, so writability comes from that bundle.
222
- const writable = bundles[lock.id]?.writable === true;
223
- if (!writable && startsWithin(lock.localRoot))
224
- return false;
225
- }
226
- return true;
213
+ export function isEditable(filePath, config, sources) {
214
+ const resolvedSources = sources ?? resolveSourceEntries(undefined, config ?? loadConfig());
215
+ return findSourceForPath(filePath, resolvedSources)?.writable === true;
227
216
  }
228
217
  /**
229
218
  * Build an actionable hint for the agent when a file is not editable.
230
219
  * Callers must check `isEditable()` before calling — this function
231
220
  * unconditionally returns the hint string.
232
221
  */
233
- export function buildEditHint(_filePath, assetType, assetName, origin) {
234
- // F4b output-spelling flip: emit the 0.9.0 conceptId grammar for the clone hint.
235
- const ref = displayRef({ type: assetType, name: assetName, bundleId: origin });
236
- return `This asset is managed by akm and may be overwritten on update. To edit, run: akm clone ${ref}`;
222
+ export function buildEditHint(ref) {
223
+ return `This asset is read-only under current AKM source policy. To make an editable copy, run: akm clone ${ref}`;
237
224
  }
238
225
  // ── Validation ──────────────────────────────────────────────────────────────
239
226
  const SUSPICIOUS_ROOTS = new Set(["/", "/etc", "/bin", "/sbin", "/usr", "/var", "/tmp", "/dev", "/proc", "/sys"]);
@@ -250,15 +237,6 @@ function isSuspiciousStashRoot(dir) {
250
237
  }
251
238
  return false;
252
239
  }
253
- // ── Helpers ─────────────────────────────────────────────────────────────────
254
- function isValidDirectory(dir) {
255
- try {
256
- return fs.statSync(dir).isDirectory();
257
- }
258
- catch {
259
- return false;
260
- }
261
- }
262
240
  // ── Stash cache integration ─────────────────────────────────────────────────
263
241
  /**
264
242
  * Ensure all cache-backed stash providers are refreshed so their cache
@@ -295,6 +273,17 @@ export async function ensureSourceCaches(config, options) {
295
273
  for (const entry of getSources(cfg)) {
296
274
  if (entry.enabled === false)
297
275
  continue;
276
+ const lockedRoot = lockContentRootFor(entry.name, entry.type);
277
+ if (lockedRoot) {
278
+ if (!isMaterializedDir(lockedRoot)) {
279
+ warn(`Warning: managed source "${entry.name}" is missing its locked materialization at ${lockedRoot}; ` +
280
+ `run \`akm bundle update ${entry.name}\` to restore it.`);
281
+ }
282
+ // Managed installs are refreshed only by add/update. Hydrating the URL-
283
+ // derived provider cache here would create a second checkout while reads
284
+ // and writes continue using the lock root.
285
+ continue;
286
+ }
298
287
  const factory = resolveSourceProviderFactory(entry.type);
299
288
  if (!factory)
300
289
  continue;
@@ -315,7 +304,7 @@ export async function ensureSourceCaches(config, options) {
315
304
  continue;
316
305
  }
317
306
  try {
318
- await provider.sync({ force });
307
+ await provider.sync({ force, secrets: options?.secrets });
319
308
  }
320
309
  catch (err) {
321
310
  warn(`Warning: failed to refresh ${provider.kind} source "${provider.name}": ${err instanceof Error ? err.message : String(err)}`);
@@ -355,5 +344,5 @@ function warnIfSourceUnavailableForRead(entry, providerName) {
355
344
  if (dir && isMaterializedDir(dir))
356
345
  return;
357
346
  warn(`Warning: source "${providerName}" is not materialized locally; skipping it for this read. ` +
358
- "Run `akm index` (or `akm source update`) to fetch it.");
347
+ "Run `akm index` (or `akm bundle update`) to fetch it.");
359
348
  }
@@ -1,14 +1,6 @@
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
- * Usage event helpers for telemetry and utility-based re-ranking.
6
- *
7
- * Schema (created by ensureUsageEventsSchema):
8
- * id, event_type, query, entry_id (nullable), entry_ref, signal, metadata, source, created_at
9
- */
10
- import { stashDirFor } from "../../core/asset/asset-placement.js";
11
- import { typeNameFromConceptId } from "../../core/asset/resolve-ref.js";
12
4
  const USAGE_EVENT_SOURCES = new Set(["user", "improve", "task", "audit", "unknown"]);
13
5
  /** Resolve subprocess provenance without treating an invalid value as user demand. */
14
6
  export function resolveUsageEventSource(env = process.env) {
@@ -51,88 +43,7 @@ export function insertUsageEvent(db, event) {
51
43
  /* fire-and-forget: silently ignore errors */
52
44
  }
53
45
  }
54
- /**
55
- * Bare-form candidates a bare `entry_ref` filter matches a stored row under.
56
- * The durable `usage_events.entry_ref` column straddles the F5 ref-grammar flip:
57
- * F4c-indexed rows carry the new-grammar conceptId (`memories/alpha`) while
58
- * transitional / not-yet-re-keyed rows still carry the legacy `type:name`
59
- * (`memory:alpha`). Both name the SAME asset, so a bare filter in EITHER grammar
60
- * must bridge to the other spelling — otherwise a history/telemetry query misses
61
- * half the asset's own events across the flip boundary. (Fully-qualified filters
62
- * apply this bridge under a fixed origin — see getUsageEvents.)
63
- */
64
- function usageEventBareCandidates(ref) {
65
- const trimmed = ref.trim();
66
- const out = new Set([trimmed]);
67
- // New-grammar conceptId (`memories/alpha`) → its legacy `type:name` sibling.
68
- const legacy = typeNameFromConceptId(trimmed);
69
- if (legacy)
70
- out.add(`${legacy.type}:${legacy.name}`);
71
- // Legacy `type:name` (`memory:alpha`) → its new-grammar `stashDir/name` sibling.
72
- const colon = trimmed.indexOf(":");
73
- if (colon > 0) {
74
- const dir = stashDirFor(trimmed.slice(0, colon));
75
- if (dir)
76
- out.add(`${dir}/${trimmed.slice(colon + 1)}`);
77
- }
78
- return [...out];
79
- }
80
46
  // ── Query ────────────────────────────────────────────────────────────────────
81
- /**
82
- * Retrieve usage events, optionally filtered by event_type and/or entry_ref.
83
- */
84
- export function getUsageEvents(db, filters) {
85
- const conditions = [];
86
- const params = [];
87
- if (filters?.event_type) {
88
- conditions.push("event_type = ?");
89
- params.push(filters.event_type);
90
- }
91
- if (filters?.entry_ref) {
92
- if (filters.entry_ref.includes("//")) {
93
- // Fully-qualified filter (`bundle//conceptId` or legacy `origin//type:name`)
94
- // — the user named a specific bundle/origin, so match that origin exactly,
95
- // but bridge the bare tail across the F5 grammar flip (see
96
- // usageEventBareCandidates) so a `stash//memories/alpha` filter also matches
97
- // an un-re-keyed `stash//memory:alpha` row (and vice versa).
98
- const boundary = filters.entry_ref.indexOf("//");
99
- const origin = filters.entry_ref.slice(0, boundary);
100
- const bareTail = filters.entry_ref.slice(boundary + 2);
101
- const quals = usageEventBareCandidates(bareTail).map((bare) => `${origin}//${bare}`);
102
- conditions.push(`entry_ref IN (${quals.map(() => "?").join(", ")})`);
103
- params.push(...quals);
104
- }
105
- else {
106
- // Bare filter — match the stored bare form (everything after the first
107
- // `//`, or the whole value when un-qualified) against the conceptId the
108
- // filter normalizes to.
109
- const candidates = usageEventBareCandidates(filters.entry_ref);
110
- const placeholders = candidates.map(() => "?").join(", ");
111
- conditions.push(`(CASE WHEN instr(entry_ref, '//') > 0 THEN substr(entry_ref, instr(entry_ref, '//') + 2) ELSE entry_ref END) ` +
112
- `IN (${placeholders})`);
113
- params.push(...candidates);
114
- }
115
- }
116
- if (filters?.source) {
117
- if (filters.source === "unknown") {
118
- conditions.push("(source = 'unknown' OR source IS NULL OR source = '')");
119
- }
120
- else {
121
- conditions.push("source = ?");
122
- params.push(filters.source);
123
- }
124
- }
125
- if (filters?.since) {
126
- conditions.push("created_at >= ?");
127
- params.push(filters.since);
128
- }
129
- const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
130
- const sql = `SELECT id, event_type, query, entry_id, entry_ref, signal, metadata, source, created_at
131
- FROM usage_events ${where}
132
- ORDER BY id ASC`;
133
- const rows = db.prepare(sql).all(...params);
134
- return rows.map((row) => ({ ...row, source: row.source || "unknown" }));
135
- }
136
47
  /**
137
48
  * Aggregate positive/negative feedback counts for a single entry.
138
49
  *
@@ -107,11 +107,12 @@ export async function getAllRenderers() {
107
107
  * Build a RenderContext by merging a FileContext with its winning MatchResult
108
108
  * and the list of stash search paths.
109
109
  */
110
- export function buildRenderContext(ctx, match, stashDirs, origin) {
110
+ export function buildRenderContext(ctx, match, stashDirs, origin, defaultBundle) {
111
111
  return {
112
112
  ...ctx,
113
113
  matchResult: match,
114
114
  stashDirs,
115
115
  origin,
116
+ defaultBundle,
116
117
  };
117
118
  }