akm-cli 0.9.0-rc.0 → 0.9.0-rc.13

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 (598) hide show
  1. package/CHANGELOG.md +1283 -22
  2. package/README.md +62 -37
  3. package/SECURITY.md +46 -31
  4. package/dist/akm +162 -38
  5. package/dist/akm-migrate +44 -0
  6. package/dist/assets/backends/schtasks-template.xml +2 -1
  7. package/dist/assets/hints/cli-hints-full.md +268 -118
  8. package/dist/assets/hints/cli-hints-short.md +87 -24
  9. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  11. package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
  12. package/dist/assets/improve-strategies/frequent.json +15 -0
  13. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  14. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  15. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
  16. package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
  17. package/dist/assets/improve-strategies/reflect-distill.json +30 -0
  18. package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
  19. package/dist/assets/prompts/consolidate-system.md +5 -5
  20. package/dist/assets/prompts/extract-session.md +2 -6
  21. package/dist/assets/prompts/memory-infer-user.md +2 -3
  22. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  23. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  24. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  25. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  26. package/dist/assets/stash-skeleton/README.md +38 -10
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  39. package/dist/assets/tasks/core/extract.yml +3 -2
  40. package/dist/assets/tasks/core/improve.yml +2 -1
  41. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  42. package/dist/assets/tasks/core/sync.yml +1 -0
  43. package/dist/assets/tasks/core/version-check.yml +2 -1
  44. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  45. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  46. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  48. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  49. package/dist/assets/templates/html/health.html +5 -4
  50. package/dist/assets/workflows/workflow-template.md +31 -15
  51. package/dist/cli/invocation.js +279 -0
  52. package/dist/cli/parse-args.js +5 -90
  53. package/dist/cli/retired-commands.js +78 -0
  54. package/dist/cli/shared.js +158 -48
  55. package/dist/cli-node.mjs +2 -1
  56. package/dist/cli.js +747 -293
  57. package/dist/commands/agent/agent-dispatch.js +19 -18
  58. package/dist/commands/agent/agent-support.js +0 -24
  59. package/dist/commands/agent/contribute-cli.js +43 -97
  60. package/dist/commands/completions.js +80 -23
  61. package/dist/commands/config-cli.js +44 -281
  62. package/dist/commands/env/env-binding.js +99 -0
  63. package/dist/commands/env/env-cli.js +84 -224
  64. package/dist/commands/env/env.js +12 -163
  65. package/dist/commands/env/marker-path.js +6 -0
  66. package/dist/commands/env/secret-cli.js +45 -61
  67. package/dist/commands/env/secret.js +32 -62
  68. package/dist/commands/feedback-cli.js +179 -85
  69. package/dist/commands/health/accept-rate.js +58 -0
  70. package/dist/commands/health/advisories.js +7 -8
  71. package/dist/commands/health/checks.js +279 -94
  72. package/dist/commands/health/html-report.js +197 -578
  73. package/dist/commands/health/improve-metrics.js +277 -246
  74. package/dist/commands/health/llm-usage.js +19 -19
  75. package/dist/commands/health/md-report.js +16 -7
  76. package/dist/commands/health/metrics.js +67 -32
  77. package/dist/commands/health/renderers.js +47 -0
  78. package/dist/commands/health/report-view-model.js +508 -0
  79. package/dist/commands/health/stash-exposure.js +1 -1
  80. package/dist/commands/health/surfaces.js +16 -56
  81. package/dist/commands/health/task-runs.js +3 -67
  82. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  83. package/dist/commands/health/types-improve.js +29 -0
  84. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  85. package/dist/commands/health/types-result.js +7 -0
  86. package/dist/commands/health/types-runs.js +4 -0
  87. package/dist/commands/health/types-session-log.js +4 -0
  88. package/dist/commands/health/types-windows.js +4 -0
  89. package/dist/commands/health/types.js +26 -21
  90. package/dist/commands/health/windows.js +2 -3
  91. package/dist/commands/health.js +296 -167
  92. package/dist/commands/improve/anti-collapse.js +5 -5
  93. package/dist/commands/improve/autonomy-gate.js +68 -0
  94. package/dist/commands/improve/collapse-detector.js +65 -52
  95. package/dist/commands/improve/consolidate/chunking.js +9 -7
  96. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  97. package/dist/commands/improve/consolidate/merge.js +4 -0
  98. package/dist/commands/improve/consolidate.js +454 -1354
  99. package/dist/commands/improve/content-hash.js +39 -0
  100. package/dist/commands/improve/distill/content-repair.js +4 -10
  101. package/dist/commands/improve/distill/promote-memory.js +89 -64
  102. package/dist/commands/improve/distill/quality-gate.js +118 -42
  103. package/dist/commands/improve/distill-guards.js +1 -1
  104. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  105. package/dist/commands/improve/distill.js +607 -363
  106. package/dist/commands/improve/eligibility.js +165 -79
  107. package/dist/commands/improve/extract-cli.js +35 -126
  108. package/dist/commands/improve/extract-prompt.js +6 -35
  109. package/dist/commands/improve/extract.js +640 -391
  110. package/dist/commands/improve/feedback-valence.js +2 -12
  111. package/dist/commands/improve/improve-cli.js +134 -135
  112. package/dist/commands/improve/improve-result-file.js +30 -50
  113. package/dist/commands/improve/improve-run-types.js +4 -0
  114. package/dist/commands/improve/improve-strategies.js +135 -0
  115. package/dist/commands/improve/improve.js +904 -701
  116. package/dist/commands/improve/locks.js +64 -111
  117. package/dist/commands/improve/loop-stages.js +1110 -923
  118. package/dist/commands/improve/memory/derived-ref.js +124 -0
  119. package/dist/commands/improve/memory/memory-belief.js +79 -7
  120. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  121. package/dist/commands/improve/memory/memory-improve.js +25 -37
  122. package/dist/commands/improve/outcome-loop.js +25 -88
  123. package/dist/commands/improve/preparation.js +1034 -813
  124. package/dist/commands/improve/proactive-maintenance.js +34 -9
  125. package/dist/commands/improve/proposal-envelope.js +31 -0
  126. package/dist/commands/improve/reflect.js +983 -794
  127. package/dist/commands/improve/run-context.js +119 -0
  128. package/dist/commands/improve/salience.js +24 -127
  129. package/dist/commands/improve/session-asset.js +7 -3
  130. package/dist/commands/improve/shared.js +14 -34
  131. package/dist/commands/improve/source-identity.js +28 -0
  132. package/dist/commands/improve/triage.js +20 -17
  133. package/dist/commands/lint/base-linter.js +340 -313
  134. package/dist/commands/lint/env-key-rules.js +31 -47
  135. package/dist/commands/lint/index.js +185 -30
  136. package/dist/commands/{events.js → log.js} +28 -38
  137. package/dist/commands/migrate-cli.js +54 -0
  138. package/dist/commands/migration-tool.js +55 -0
  139. package/dist/commands/observability-cli.js +70 -208
  140. package/dist/commands/proposal/diff-format.js +50 -0
  141. package/dist/commands/proposal/drain-policies.js +0 -6
  142. package/dist/commands/proposal/drain.js +91 -40
  143. package/dist/commands/proposal/proposal-cli.js +134 -132
  144. package/dist/commands/proposal/proposal-types.js +56 -0
  145. package/dist/commands/proposal/proposal.js +83 -65
  146. package/dist/commands/proposal/propose-cli.js +88 -0
  147. package/dist/commands/proposal/propose.js +105 -88
  148. package/dist/commands/proposal/repository.js +1303 -278
  149. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  150. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  151. package/dist/commands/proposal/validators/proposals.js +6 -8
  152. package/dist/commands/read/curate.js +78 -73
  153. package/dist/commands/read/knowledge.js +510 -13
  154. package/dist/commands/read/registry-search.js +2 -2
  155. package/dist/commands/read/remember-cli.js +84 -15
  156. package/dist/commands/read/search-cli.js +203 -96
  157. package/dist/commands/read/search.js +126 -94
  158. package/dist/commands/read/show.js +226 -250
  159. package/dist/commands/registry-cli.js +34 -60
  160. package/dist/commands/remember.js +18 -57
  161. package/dist/commands/sources/add-cli.js +104 -49
  162. package/dist/commands/sources/bundle-cli.js +166 -0
  163. package/dist/commands/sources/bundle-config-ops.js +63 -0
  164. package/dist/commands/sources/info.js +27 -15
  165. package/dist/commands/sources/init.js +30 -40
  166. package/dist/commands/sources/installed-stashes.js +469 -172
  167. package/dist/commands/sources/migration-help.js +7 -4
  168. package/dist/commands/sources/schema-repair.js +10 -9
  169. package/dist/commands/sources/self-update.js +182 -121
  170. package/dist/commands/sources/source-add.js +169 -178
  171. package/dist/commands/sources/source-clone.js +144 -41
  172. package/dist/commands/sources/source-manage.js +94 -59
  173. package/dist/commands/sources/sources-cli.js +64 -205
  174. package/dist/commands/sources/stash-cli.js +91 -54
  175. package/dist/commands/sources/stash-skeleton.js +1 -1
  176. package/dist/commands/tasks/tasks-cli.js +106 -104
  177. package/dist/commands/tasks/tasks.js +445 -262
  178. package/dist/commands/workflow-cli.js +232 -121
  179. package/dist/core/action-contributors.js +1 -1
  180. package/dist/core/activation-policy.js +49 -0
  181. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  182. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  183. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  184. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  185. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  186. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  187. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  188. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  189. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  190. package/dist/core/adapter/adapters/index.js +80 -0
  191. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  192. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  193. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  194. package/dist/core/adapter/adapters/shared.js +286 -0
  195. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  196. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  197. package/dist/core/adapter/bundle-adapter.js +4 -0
  198. package/dist/core/adapter/detect-adapter.js +17 -0
  199. package/dist/core/adapter/recognize-match.js +44 -0
  200. package/dist/core/adapter/registry.js +56 -0
  201. package/dist/core/adapter/types.js +4 -0
  202. package/dist/core/asset/akm-markdown.js +30 -0
  203. package/dist/core/asset/asset-placement.js +243 -0
  204. package/dist/core/asset/asset-ref.js +110 -79
  205. package/dist/core/asset/asset-serialize.js +20 -0
  206. package/dist/core/asset/frontmatter.js +28 -12
  207. package/dist/core/asset/markdown.js +40 -51
  208. package/dist/core/asset/resolve-ref.js +274 -0
  209. package/dist/core/asset/stash-meta.js +2 -2
  210. package/dist/core/bundle-id.js +51 -0
  211. package/dist/core/common.js +281 -86
  212. package/dist/core/config/config-io.js +42 -128
  213. package/dist/core/config/config-schema.js +233 -834
  214. package/dist/core/config/config-sources.js +162 -39
  215. package/dist/core/config/config-types.js +16 -11
  216. package/dist/core/config/config-version.js +29 -0
  217. package/dist/core/config/config-walker.js +126 -37
  218. package/dist/core/config/config.js +154 -331
  219. package/dist/core/config/deep-merge.js +41 -0
  220. package/dist/core/config/engine-semantics.js +28 -0
  221. package/dist/core/config/experimental.js +21 -0
  222. package/dist/core/config/schema/embedding.js +38 -0
  223. package/dist/core/config/schema/engines.js +116 -0
  224. package/dist/core/config/schema/experimental.js +47 -0
  225. package/dist/core/config/schema/feedback.js +31 -0
  226. package/dist/core/config/schema/improve-processes.js +389 -0
  227. package/dist/core/config/schema/improve.js +94 -0
  228. package/dist/core/config/schema/index-config.js +176 -0
  229. package/dist/core/config/schema/output.js +18 -0
  230. package/dist/core/config/schema/primitives.js +94 -0
  231. package/dist/core/config/schema/search.js +30 -0
  232. package/dist/core/config/schema/setup.js +18 -0
  233. package/dist/core/config/schema/sources-bundles.js +169 -0
  234. package/dist/core/config/schema/workflow.js +29 -0
  235. package/dist/core/env-secret-ref.js +155 -20
  236. package/dist/core/errors.js +17 -15
  237. package/dist/core/events-types.js +4 -0
  238. package/dist/core/events.js +46 -128
  239. package/dist/core/extra-params.js +62 -0
  240. package/dist/core/file-change.js +17 -0
  241. package/dist/core/file-lock.js +202 -57
  242. package/dist/core/fs-txn.js +392 -0
  243. package/dist/core/git-message.js +59 -0
  244. package/dist/core/improve-result.js +167 -0
  245. package/dist/core/json-schema.js +142 -0
  246. package/dist/core/lesson-lint.js +1 -17
  247. package/dist/core/logs-db.js +1 -1
  248. package/dist/core/maintenance-barrier.js +135 -0
  249. package/dist/core/migration-operation.js +44 -0
  250. package/dist/core/mutation-target.js +78 -0
  251. package/dist/core/paths.js +22 -25
  252. package/dist/core/platform.js +10 -0
  253. package/dist/core/recognition-util.js +128 -0
  254. package/dist/core/redaction.js +392 -0
  255. package/dist/core/standards/resolve-standards-context.js +36 -65
  256. package/dist/core/standards/resolve-stash-standards.js +2 -2
  257. package/dist/core/standards/resolve-type-conventions.js +5 -5
  258. package/dist/core/state/migrations.js +242 -11
  259. package/dist/core/state-db.js +98 -10
  260. package/dist/core/structured.js +1 -1
  261. package/dist/core/subprocess.js +303 -0
  262. package/dist/core/text-truncation.js +9 -5
  263. package/dist/core/time.js +20 -0
  264. package/dist/core/type-presentation.js +130 -0
  265. package/dist/core/warn.js +0 -3
  266. package/dist/core/write-source.js +834 -118
  267. package/dist/indexer/bundle-identity-guard.js +92 -0
  268. package/dist/indexer/db/graph-db.js +1 -25
  269. package/dist/indexer/db/llm-cache.js +1 -1
  270. package/dist/indexer/ensure-index.js +30 -9
  271. package/dist/indexer/graph/graph-boost.js +9 -30
  272. package/dist/indexer/graph/graph-extraction.js +41 -27
  273. package/dist/indexer/graph/graph-types.js +4 -0
  274. package/dist/indexer/index-writer-lock.js +93 -49
  275. package/dist/indexer/index-written-assets.js +100 -53
  276. package/dist/indexer/indexer.js +746 -329
  277. package/dist/indexer/init.js +18 -25
  278. package/dist/indexer/installations.js +142 -0
  279. package/dist/indexer/passes/dir-staleness.js +18 -10
  280. package/dist/indexer/passes/memory-inference.js +25 -15
  281. package/dist/indexer/passes/metadata.js +412 -243
  282. package/dist/indexer/scan/doc-to-entry.js +160 -0
  283. package/dist/indexer/scan/drain-dir.js +134 -0
  284. package/dist/indexer/search/db-search.js +292 -108
  285. package/dist/indexer/search/fts-query.js +64 -0
  286. package/dist/indexer/search/ranking-contributors.js +145 -25
  287. package/dist/indexer/search/ranking-types.js +4 -0
  288. package/dist/indexer/search/ranking.js +28 -71
  289. package/dist/indexer/search/search-attribution.js +67 -0
  290. package/dist/indexer/search/search-fields.js +18 -3
  291. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  292. package/dist/indexer/search/search-source.js +157 -111
  293. package/dist/indexer/search/semantic-status.js +4 -1
  294. package/dist/indexer/usage/usage-events.js +10 -30
  295. package/dist/indexer/walk/file-context.js +3 -45
  296. package/dist/indexer/walk/matchers.js +42 -34
  297. package/dist/indexer/walk/path-resolver.js +11 -5
  298. package/dist/indexer/walk/walker.js +42 -14
  299. package/dist/integrations/agent/builder-shared.js +7 -0
  300. package/dist/integrations/agent/builders.js +5 -56
  301. package/dist/integrations/agent/config.js +3 -143
  302. package/dist/integrations/agent/detect.js +17 -2
  303. package/dist/integrations/agent/engine-resolution.js +231 -0
  304. package/dist/integrations/agent/index.js +1 -2
  305. package/dist/integrations/agent/model-aliases.js +16 -2
  306. package/dist/integrations/agent/profiles.js +36 -62
  307. package/dist/integrations/agent/prompts.js +46 -18
  308. package/dist/integrations/agent/runner-dispatch.js +93 -4
  309. package/dist/integrations/agent/runner.js +76 -208
  310. package/dist/integrations/agent/spawn.js +88 -196
  311. package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
  312. package/dist/integrations/harnesses/aider/index.js +48 -0
  313. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  314. package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
  315. package/dist/integrations/harnesses/amazonq/index.js +45 -0
  316. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  317. package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
  318. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  319. package/dist/integrations/harnesses/claude/index.js +24 -35
  320. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  321. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  322. package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
  323. package/dist/integrations/harnesses/codex/index.js +52 -0
  324. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  325. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  326. package/dist/integrations/harnesses/copilot/index.js +48 -0
  327. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  328. package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
  329. package/dist/integrations/harnesses/gemini/index.js +48 -0
  330. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  331. package/dist/integrations/harnesses/ids.js +24 -0
  332. package/dist/integrations/harnesses/index.js +54 -34
  333. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  334. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  335. package/dist/integrations/harnesses/opencode/index.js +14 -32
  336. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  337. package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
  338. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
  339. package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
  340. package/dist/integrations/harnesses/openhands/index.js +48 -0
  341. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  342. package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
  343. package/dist/integrations/harnesses/pi/index.js +45 -0
  344. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  345. package/dist/integrations/harnesses/shared.js +17 -0
  346. package/dist/integrations/harnesses/types.js +43 -32
  347. package/dist/integrations/lockfile.js +211 -24
  348. package/dist/integrations/session-logs/index.js +36 -39
  349. package/dist/integrations/session-logs/provider-base.js +113 -0
  350. package/dist/llm/client.js +182 -110
  351. package/dist/llm/embedders/deterministic.js +2 -2
  352. package/dist/llm/embedders/remote.js +21 -9
  353. package/dist/llm/feature-gate.js +17 -57
  354. package/dist/llm/graph-extract.js +12 -13
  355. package/dist/llm/index-passes.js +8 -42
  356. package/dist/llm/memory-infer.js +144 -1
  357. package/dist/llm/metadata-enhance.js +45 -30
  358. package/dist/llm/structured-call.js +16 -8
  359. package/dist/llm/usage-persist.js +30 -5
  360. package/dist/llm/usage-telemetry.js +59 -6
  361. package/dist/output/cli-hints.js +1 -2
  362. package/dist/output/command-registry.js +27 -0
  363. package/dist/output/context.js +22 -7
  364. package/dist/output/format-exempt.js +80 -0
  365. package/dist/output/generic-render.js +251 -0
  366. package/dist/output/html-render.js +11 -16
  367. package/dist/output/render-registry.js +57 -0
  368. package/dist/output/renderers.js +14 -279
  369. package/dist/output/shapes/curate.js +10 -1
  370. package/dist/output/shapes/events.js +12 -7
  371. package/dist/output/shapes/helpers.js +58 -84
  372. package/dist/output/shapes/passthrough.js +11 -39
  373. package/dist/output/shapes/proposal/producer.js +15 -7
  374. package/dist/output/shapes/registry.js +12 -6
  375. package/dist/output/shapes.js +0 -9
  376. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  377. package/dist/output/text/bundle-show.js +7 -0
  378. package/dist/output/text/command-format.js +562 -0
  379. package/dist/output/text/env.js +1 -3
  380. package/dist/output/text/events.js +8 -7
  381. package/dist/output/text/helpers.js +15 -1164
  382. package/dist/output/text/proposal/producer.js +4 -2
  383. package/dist/output/text/proposal-format.js +202 -0
  384. package/dist/output/text/registry-commands.js +1 -2
  385. package/dist/output/text/registry.js +12 -6
  386. package/dist/output/text/show-directives.js +117 -0
  387. package/dist/output/text/show-format.js +103 -0
  388. package/dist/output/text/sync.js +5 -0
  389. package/dist/output/text/workflow-format.js +332 -0
  390. package/dist/output/text/workflow.js +3 -2
  391. package/dist/output/text.js +10 -19
  392. package/dist/registry/factory.js +4 -6
  393. package/dist/registry/origin-resolve.js +16 -27
  394. package/dist/registry/providers/skills-sh.js +3 -3
  395. package/dist/registry/providers/static-index.js +15 -25
  396. package/dist/registry/resolve.js +43 -94
  397. package/dist/registry/semver.js +43 -0
  398. package/dist/runtime.js +81 -12
  399. package/dist/scripts/akm-migrate.js +35529 -0
  400. package/dist/setup/detect.js +5 -7
  401. package/dist/setup/detected-engines.js +136 -0
  402. package/dist/setup/engine-config.js +100 -0
  403. package/dist/setup/registry-stash-loader.js +3 -3
  404. package/dist/setup/semantic-assets.js +12 -9
  405. package/dist/setup/setup.js +444 -208
  406. package/dist/setup/steps/connection-shared.js +120 -0
  407. package/dist/setup/steps/connection.js +108 -305
  408. package/dist/setup/steps/platforms.js +13 -12
  409. package/dist/setup/steps/semantic.js +15 -3
  410. package/dist/setup/steps/sources.js +21 -15
  411. package/dist/setup/steps/stashdir.js +6 -4
  412. package/dist/setup/steps/tasks.js +236 -119
  413. package/dist/setup/steps.js +3 -2
  414. package/dist/sources/freshness.js +39 -0
  415. package/dist/sources/provider-factory.js +11 -17
  416. package/dist/sources/providers/filesystem.js +2 -3
  417. package/dist/sources/providers/git-install.js +278 -34
  418. package/dist/sources/providers/git-provider.js +54 -56
  419. package/dist/sources/providers/git-stash.js +420 -91
  420. package/dist/sources/providers/git.js +2 -2
  421. package/dist/sources/providers/npm.js +16 -19
  422. package/dist/sources/providers/provider-utils.js +47 -22
  423. package/dist/sources/providers/sync-from-ref.js +3 -9
  424. package/dist/sources/providers/website.js +2 -2
  425. package/dist/sources/resolve.js +11 -10
  426. package/dist/sources/snapshot-fetchers/types.js +4 -0
  427. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  428. package/dist/storage/database.js +60 -4
  429. package/dist/storage/engines/sqlite-migrations.js +156 -5
  430. package/dist/storage/locations.js +1 -2
  431. package/dist/storage/repositories/canaries-repository.js +1 -1
  432. package/dist/storage/repositories/events-repository.js +51 -11
  433. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  434. package/dist/storage/repositories/index-connection.js +79 -0
  435. package/dist/storage/repositories/index-db.js +4 -3
  436. package/dist/storage/repositories/index-entries-repository.js +863 -0
  437. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  438. package/dist/storage/repositories/index-entry-types.js +4 -0
  439. package/dist/storage/repositories/index-fts-repository.js +167 -0
  440. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  441. package/dist/storage/repositories/index-meta-repository.js +49 -0
  442. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  443. package/dist/storage/repositories/index-sql.js +12 -0
  444. package/dist/storage/repositories/index-utility-repository.js +356 -0
  445. package/dist/storage/repositories/index-vec-repository.js +250 -0
  446. package/dist/storage/repositories/outcome-repository.js +119 -0
  447. package/dist/storage/repositories/proposals-repository.js +317 -75
  448. package/dist/storage/repositories/registry-cache.js +1 -1
  449. package/dist/storage/repositories/salience-repository.js +172 -0
  450. package/dist/storage/repositories/task-history-repository.js +110 -3
  451. package/dist/storage/repositories/workflow-runs-repository.js +240 -19
  452. package/dist/tasks/backends/cron.js +169 -46
  453. package/dist/tasks/backends/exec-utils.js +76 -3
  454. package/dist/tasks/backends/index.js +6 -9
  455. package/dist/tasks/backends/launchd.js +292 -55
  456. package/dist/tasks/backends/schtasks.js +557 -70
  457. package/dist/tasks/backends/types.js +4 -0
  458. package/dist/tasks/command-executable.js +93 -0
  459. package/dist/tasks/embedded.js +56 -38
  460. package/dist/tasks/parser.js +156 -64
  461. package/dist/tasks/resolve-akm-bin.js +144 -51
  462. package/dist/tasks/runner.js +377 -209
  463. package/dist/tasks/schedule.js +108 -19
  464. package/dist/tasks/scheduler-invocation.js +296 -0
  465. package/dist/tasks/schema.js +1 -1
  466. package/dist/tasks/task-id.js +35 -0
  467. package/dist/tasks/validator.js +30 -16
  468. package/dist/text-import-hook.mjs +1 -1
  469. package/dist/workflows/authoring/authoring.js +104 -43
  470. package/dist/workflows/authoring/scope-key.js +1 -1
  471. package/dist/workflows/cli.js +0 -16
  472. package/dist/workflows/concurrency-policy.js +15 -0
  473. package/dist/workflows/exec/brief.js +450 -0
  474. package/dist/workflows/exec/frozen-judge.js +47 -0
  475. package/dist/workflows/exec/native-executor.js +1038 -0
  476. package/dist/workflows/exec/param-secrets.js +115 -0
  477. package/dist/workflows/exec/report.js +1460 -0
  478. package/dist/workflows/exec/run-workflow.js +602 -0
  479. package/dist/workflows/exec/scheduler.js +71 -0
  480. package/dist/workflows/exec/step-work.js +1190 -0
  481. package/dist/workflows/exec/unit-writer.js +23 -0
  482. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  483. package/dist/workflows/exec/worktree.js +171 -0
  484. package/dist/workflows/ir/compile.js +246 -0
  485. package/dist/workflows/ir/freeze.js +233 -0
  486. package/dist/workflows/ir/params.js +54 -0
  487. package/dist/workflows/ir/plan-hash.js +68 -0
  488. package/dist/workflows/ir/schema.js +540 -0
  489. package/dist/workflows/parser.js +878 -304
  490. package/dist/workflows/program/expressions.js +181 -0
  491. package/dist/workflows/program/schema.js +51 -0
  492. package/dist/workflows/renderer.js +100 -45
  493. package/dist/workflows/resource-limits.js +22 -0
  494. package/dist/workflows/runtime/agent-identity.js +59 -14
  495. package/dist/workflows/runtime/checkin.js +1 -1
  496. package/dist/workflows/runtime/plan-classifier.js +131 -0
  497. package/dist/workflows/runtime/runs.js +376 -119
  498. package/dist/workflows/runtime/unit-checkin.js +45 -0
  499. package/dist/workflows/runtime/unit-phases.js +20 -0
  500. package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
  501. package/dist/workflows/schema.js +1 -11
  502. package/dist/workflows/validate-summary.js +2 -3
  503. package/dist/workflows/validator.js +52 -30
  504. package/docs/README.md +42 -78
  505. package/docs/migration/README.md +8 -0
  506. package/docs/migration/release-notes/0.6.0.md +1 -1
  507. package/docs/migration/release-notes/0.7.0.md +9 -8
  508. package/docs/migration/release-notes/0.9.0.md +158 -14
  509. package/docs/migration/v0.7-to-v0.8.md +46 -47
  510. package/docs/migration/v0.8-to-v0.9.md +844 -0
  511. package/docs/reference/README.md +12 -0
  512. package/docs/reference/data-and-telemetry.md +333 -0
  513. package/package.json +21 -17
  514. package/schemas/akm-asset-envelope.json +93 -0
  515. package/schemas/akm-config.json +4636 -0
  516. package/schemas/akm-task.json +87 -0
  517. package/schemas/akm-workflow.json +373 -0
  518. package/dist/akm-migrate-storage +0 -38
  519. package/dist/assets/help/help-accept.md +0 -12
  520. package/dist/assets/help/help-improve.md +0 -84
  521. package/dist/assets/help/help-proposals.md +0 -17
  522. package/dist/assets/help/help-propose.md +0 -17
  523. package/dist/assets/help/help-reject.md +0 -11
  524. package/dist/assets/profiles/frequent.json +0 -13
  525. package/dist/assets/profiles/recombine-only.json +0 -21
  526. package/dist/assets/profiles/reflect-distill.json +0 -30
  527. package/dist/assets/profiles/synthesize.json +0 -15
  528. package/dist/assets/prompts/procedural-system.md +0 -44
  529. package/dist/assets/prompts/recombine-system.md +0 -40
  530. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  531. package/dist/assets/tasks/core/backup.yml +0 -4
  532. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  533. package/dist/assets/templates/html/default.html +0 -78
  534. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  535. package/dist/assets/wiki/index-template.md +0 -12
  536. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  537. package/dist/assets/wiki/log-template.md +0 -8
  538. package/dist/assets/wiki/schema-template.md +0 -61
  539. package/dist/cli/config-migrate.js +0 -150
  540. package/dist/cli/config-validate.js +0 -39
  541. package/dist/commands/graph/graph-cli.js +0 -124
  542. package/dist/commands/graph/graph.js +0 -487
  543. package/dist/commands/improve/calibration.js +0 -161
  544. package/dist/commands/improve/dedup.js +0 -482
  545. package/dist/commands/improve/extract-watch.js +0 -140
  546. package/dist/commands/improve/hot-probation.js +0 -45
  547. package/dist/commands/improve/improve-auto-accept.js +0 -276
  548. package/dist/commands/improve/improve-profiles.js +0 -168
  549. package/dist/commands/improve/procedural.js +0 -398
  550. package/dist/commands/improve/recombine.js +0 -818
  551. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  552. package/dist/commands/lint/agent-linter.js +0 -44
  553. package/dist/commands/lint/command-linter.js +0 -44
  554. package/dist/commands/lint/default-linter.js +0 -16
  555. package/dist/commands/lint/fact-linter.js +0 -39
  556. package/dist/commands/lint/knowledge-linter.js +0 -16
  557. package/dist/commands/lint/memory-linter.js +0 -61
  558. package/dist/commands/lint/registry.js +0 -41
  559. package/dist/commands/lint/skill-linter.js +0 -45
  560. package/dist/commands/lint/task-linter.js +0 -50
  561. package/dist/commands/lint/workflow-linter.js +0 -81
  562. package/dist/commands/proposal/legacy-import.js +0 -115
  563. package/dist/commands/sources/history.js +0 -196
  564. package/dist/commands/tasks/default-tasks.js +0 -186
  565. package/dist/commands/wiki-cli.js +0 -292
  566. package/dist/core/asset/asset-registry.js +0 -76
  567. package/dist/core/asset/asset-spec.js +0 -259
  568. package/dist/core/config/config-migration.js +0 -602
  569. package/dist/core/deep-merge.js +0 -38
  570. package/dist/core/eval/rank-metrics.js +0 -113
  571. package/dist/core/ripgrep/install.js +0 -163
  572. package/dist/core/ripgrep/resolve.js +0 -81
  573. package/dist/indexer/db/db.js +0 -1413
  574. package/dist/indexer/manifest.js +0 -170
  575. package/dist/indexer/passes/metadata-contributors.js +0 -31
  576. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  577. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
  578. package/dist/llm/call-ai.js +0 -62
  579. package/dist/llm/memory-infer-impl.js +0 -138
  580. package/dist/output/shapes/distill.js +0 -14
  581. package/dist/output/shapes/history.js +0 -11
  582. package/dist/output/text/distill.js +0 -6
  583. package/dist/output/text/enable-disable.js +0 -8
  584. package/dist/output/text/history.js +0 -6
  585. package/dist/output/text/wiki.js +0 -16
  586. package/dist/registry/build-index.js +0 -386
  587. package/dist/scripts/migrate-storage.js +0 -19108
  588. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
  589. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  590. package/dist/setup/legacy-config.js +0 -106
  591. package/dist/storage/repositories/consolidation-repository.js +0 -38
  592. package/dist/storage/repositories/recombine-repository.js +0 -213
  593. package/dist/wiki/wiki-templates.js +0 -15
  594. package/dist/wiki/wiki.js +0 -1012
  595. package/dist/workflows/db.js +0 -215
  596. package/docs/data-and-telemetry.md +0 -226
  597. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  598. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -1,20 +1,21 @@
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 { deepMergeConfig } from "../core/config/deep-merge.js";
4
5
  /**
5
6
  * Build a fresh `SetupContext` over a starting config. The returned context
6
7
  * applies deltas in-place onto an internal accumulator and exposes the
7
8
  * latest snapshot via `ctx.config`.
8
9
  */
9
10
  export function createSetupContext(initial, options) {
10
- let acc = { ...initial };
11
+ let acc = deepMergeConfig({}, initial);
11
12
  return {
12
13
  get config() {
13
14
  return acc;
14
15
  },
15
16
  nonInteractive: options.nonInteractive,
16
17
  apply(delta) {
17
- acc = { ...acc, ...delta };
18
+ acc = deepMergeConfig(acc, delta);
18
19
  },
19
20
  };
20
21
  }
@@ -0,0 +1,39 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Shared freshness-window skeleton for mirror caches (git repos, website
6
+ * snapshots). A marker file's mtime records the last successful refresh:
7
+ * within `ttlMs` the cached copy is served without refreshing; on refresh
8
+ * failure the cached copy is still served while the marker is younger than
9
+ * `staleMs`, so search stays available through upstream outages.
10
+ */
11
+ import fs from "node:fs";
12
+ import { isExpired } from "./providers/provider-utils.js";
13
+ /**
14
+ * Run the fresh → refresh → stale-fallback ladder around `refresh()`.
15
+ * Resolves when the cached copy is usable (fresh, refreshed, or stale-but-
16
+ * within-window); rethrows the refresh error otherwise.
17
+ */
18
+ export async function withFreshnessCache(options) {
19
+ const usable = options.isUsable ?? (() => true);
20
+ let mtime = 0;
21
+ try {
22
+ mtime = fs.statSync(options.markerPath).mtimeMs;
23
+ }
24
+ catch {
25
+ /* no marker — never successfully refreshed */
26
+ }
27
+ if (!options.force && mtime && !isExpired(mtime, options.ttlMs) && usable()) {
28
+ return;
29
+ }
30
+ try {
31
+ await options.refresh();
32
+ }
33
+ catch (err) {
34
+ if (options.allowStaleOnRefreshFailure !== false && mtime && !isExpired(mtime, options.staleMs) && usable()) {
35
+ return;
36
+ }
37
+ throw err;
38
+ }
39
+ }
@@ -1,7 +1,17 @@
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 { getSources } from "../core/config/config.js";
4
+ /**
5
+ * Source provider factory map.
6
+ *
7
+ * Maps source kind identifiers (e.g. "filesystem", "git", "website", "npm")
8
+ * to factory functions that build {@link SourceProvider} instances from a
9
+ * {@link SourceConfigEntry}.
10
+ *
11
+ * Distinct from the registry-discovery factory (`registry/factory.ts`).
12
+ * Both share `create-provider-registry.ts` for the underlying string→factory
13
+ * map.
14
+ */
5
15
  import { createProviderRegistry } from "../registry/create-provider-registry.js";
6
16
  // ── Factory map ─────────────────────────────────────────────────────────────
7
17
  const registry = createProviderRegistry();
@@ -11,19 +21,3 @@ export function registerSourceProvider(type, factory) {
11
21
  export function resolveSourceProviderFactory(type) {
12
22
  return registry.resolve(type);
13
23
  }
14
- /**
15
- * Build a {@link SourceProvider} for every enabled source in the config that
16
- * has a registered factory.
17
- */
18
- export function resolveSourceProviders(config) {
19
- const providers = [];
20
- for (const entry of getSources(config)) {
21
- if (entry.enabled === false)
22
- continue;
23
- const factory = registry.resolve(entry.type);
24
- if (factory) {
25
- providers.push(factory(entry));
26
- }
27
- }
28
- return providers;
29
- }
@@ -7,9 +7,8 @@ import { registerSourceProvider } from "../provider-factory.js";
7
7
  /**
8
8
  * Filesystem source — points at a directory the user already manages.
9
9
  *
10
- * Implements the v1 {@link SourceProvider} interface (spec §2.1, §2.4):
11
- * just `{ name, kind, init, path }`. No `sync()` — content is the user's
12
- * own directory, never refreshed by akm.
10
+ * Implements {@link SourceProvider} with `{ name, kind, path }`. No `sync()`:
11
+ * content is the user's own directory, never refreshed by akm.
13
12
  */
14
13
  registerSourceProvider("filesystem", (entry) => {
15
14
  if (entry.type !== "filesystem") {
@@ -5,10 +5,11 @@ import { spawnSync } from "node:child_process";
5
5
  import { randomBytes } from "node:crypto";
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
8
+ import { isWithin } from "../../core/common.js";
8
9
  import { UsageError } from "../../core/errors.js";
9
10
  import { getRegistryCacheDir } from "../../core/paths.js";
10
11
  import { parseRegistryRef, resolveRegistryArtifact, validateGitRef, validateGitUrl } from "../../registry/resolve.js";
11
- import { applyAkmIncludeConfig, buildInstallCacheDir, copyDirectoryContents, detectStashRoot, isDirectory, } from "./provider-utils.js";
12
+ import { applyAkmIncludeConfig, buildInstallCacheDir, detectStashRoot, isDirectory } from "./provider-utils.js";
12
13
  /**
13
14
  * Shared subprocess wrapper for `git` invocations. Disables git's interactive
14
15
  * terminal prompt so a missing credential never hangs the process.
@@ -20,12 +21,109 @@ export function runGit(args, options) {
20
21
  env: { ...process.env, ...options?.env, GIT_TERMINAL_PROMPT: "0" },
21
22
  });
22
23
  }
24
+ /** Fetch and classify the current branch against its upstream without changing the worktree. */
25
+ export function inspectGitUpstream(repoDir) {
26
+ const remotes = runGit(["-C", repoDir, "remote"]);
27
+ if (remotes.status !== 0)
28
+ throw new UsageError(`Cannot inspect Git remotes at ${repoDir}: ${remotes.stderr.trim()}`);
29
+ if (!remotes.stdout.trim())
30
+ return { hasRemote: false, ahead: 0, behind: 0 };
31
+ const fetch = runGit(["-C", repoDir, "fetch", "--prune"], { timeout: 120_000 });
32
+ if (fetch.status !== 0)
33
+ throw new UsageError(`Cannot refresh Git target at ${repoDir}: ${fetch.stderr.trim()}`);
34
+ const upstream = runGit(["-C", repoDir, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"]);
35
+ if (upstream.status !== 0 || !upstream.stdout.trim()) {
36
+ throw new UsageError(`Git target at ${repoDir} has a remote but no upstream branch; configure one before writing.`);
37
+ }
38
+ const relation = gitRelation(repoDir, upstream.stdout.trim());
39
+ return { hasRemote: true, upstream: upstream.stdout.trim(), ...relation };
40
+ }
23
41
  /**
24
- * Sync mode for a one-shot install ref (`akm add github:owner/repo` or
25
- * `akm add git:url`). Runs the clone → strip → include-filter pipeline that
26
- * historically lived in `installRegistryRef()`.
42
+ * Verify the actually-cloned HEAD matches the revision resolved before the
43
+ * clone ran (R-011). This is a presence/identity check only — full
44
+ * content-digest verification across install/update is separate, larger
45
+ * scope work. `expectedRevision` may be an annotated tag's OBJECT id (which
46
+ * `git ls-remote` reports, distinct from the commit it points to), so the
47
+ * comparison peels it (`^{commit}`) before comparing against HEAD; a plain
48
+ * commit SHA peels to itself.
27
49
  */
28
- export async function syncRegistryGitRef(ref, options) {
50
+ export function verifyClonedRevision(cloneDir, url, expectedRevision) {
51
+ if (!expectedRevision)
52
+ return;
53
+ const head = runGit(["-C", cloneDir, "rev-parse", "HEAD"]);
54
+ if (head.status !== 0 || !head.stdout.trim()) {
55
+ throw new UsageError(`Failed to read cloned HEAD at ${cloneDir}: ${head.stderr.trim() || "rev-parse failed"}`);
56
+ }
57
+ const actual = head.stdout.trim();
58
+ const peeled = runGit(["-C", cloneDir, "rev-parse", `${expectedRevision}^{commit}`]);
59
+ const expectedCommit = peeled.status === 0 ? peeled.stdout.trim() : expectedRevision;
60
+ if (actual !== expectedCommit) {
61
+ throw new UsageError(`Cloned HEAD ${actual} at ${cloneDir} does not match the revision resolved from ${url} (${expectedRevision}); refusing to install a mismatched checkout.`);
62
+ }
63
+ }
64
+ function gitRelation(repoDir, target) {
65
+ const result = runGit(["-C", repoDir, "rev-list", "--left-right", "--count", `HEAD...${target}`]);
66
+ const match = result.stdout.trim().match(/^(\d+)\s+(\d+)$/);
67
+ if (result.status !== 0 || !match) {
68
+ throw new UsageError(`Cannot compare Git history at ${repoDir}: ${result.stderr.trim() || "unknown relation"}`);
69
+ }
70
+ return { ahead: Number(match[1]), behind: Number(match[2]) };
71
+ }
72
+ /** Reject a fast-forward that would replace an ignored, untracked local path. */
73
+ export function assertNoIgnoredPathOverwrite(repoDir, targetRevision) {
74
+ const ignored = runGit(["-C", repoDir, "ls-files", "--others", "--ignored", "--exclude-standard", "-z"]);
75
+ if (ignored.status !== 0) {
76
+ throw new UsageError(`Cannot inspect ignored files at ${repoDir}: ${ignored.stderr.trim()}`);
77
+ }
78
+ const ignoredPaths = ignored.stdout.split("\0").filter(Boolean);
79
+ if (ignoredPaths.length === 0)
80
+ return;
81
+ const changed = runGit(["-C", repoDir, "diff", "--name-only", "--no-renames", "-z", "HEAD", targetRevision]);
82
+ if (changed.status !== 0) {
83
+ throw new UsageError(`Cannot inspect incoming Git paths at ${repoDir}: ${changed.stderr.trim()}`);
84
+ }
85
+ const changedPaths = changed.stdout.split("\0").filter(Boolean);
86
+ const conflict = ignoredPaths.find((ignoredPath) => changedPaths.some((changedPath) => changedPath === ignoredPath ||
87
+ changedPath.startsWith(`${ignoredPath}/`) ||
88
+ ignoredPath.startsWith(`${changedPath}/`)));
89
+ if (conflict) {
90
+ throw new UsageError(`Git update would overwrite ignored local path ${path.join(repoDir, conflict)}; move or remove it before update.`);
91
+ }
92
+ }
93
+ function normalizeRemoteUrl(value) {
94
+ return value
95
+ .trim()
96
+ .replace(/\/+$/, "")
97
+ .replace(/\.git$/i, "");
98
+ }
99
+ function replaceDirectory(stagedDir, destination) {
100
+ const backup = `${destination}.backup-${randomBytes(4).toString("hex")}`;
101
+ const hadDestination = fs.existsSync(destination);
102
+ if (hadDestination)
103
+ fs.renameSync(destination, backup);
104
+ try {
105
+ fs.renameSync(stagedDir, destination);
106
+ }
107
+ catch (error) {
108
+ if (hadDestination && fs.existsSync(backup))
109
+ fs.renameSync(backup, destination);
110
+ throw error;
111
+ }
112
+ if (hadDestination) {
113
+ try {
114
+ fs.rmSync(backup, { recursive: true, force: true });
115
+ }
116
+ catch {
117
+ // The new destination is live; a stale backup is safer than reporting a
118
+ // failed replacement after the swap already succeeded.
119
+ }
120
+ }
121
+ }
122
+ /**
123
+ * Materialize a Git install ref (`akm bundle add github:owner/repo` or
124
+ * `akm bundle add git:url`) through the clone, strip, and include-filter pipeline.
125
+ */
126
+ export async function syncGitRef(ref, options) {
29
127
  const parsed = parseRegistryRef(ref);
30
128
  if (parsed.source === "github") {
31
129
  const githubRef = {
@@ -39,22 +137,40 @@ export async function syncRegistryGitRef(ref, options) {
39
137
  return { ...result, source: "github" };
40
138
  }
41
139
  if (parsed.source !== "git") {
42
- throw new UsageError(`syncRegistryGitRef requires a git: or github: ref, got "${ref}"`);
140
+ throw new UsageError(`syncGitRef requires a git: or github: ref, got "${ref}"`);
43
141
  }
44
142
  return doSyncGit(parsed, options);
45
143
  }
46
144
  async function doSyncGit(parsed, options) {
145
+ validateGitUrl(parsed.url);
146
+ if (parsed.requestedRef)
147
+ validateGitRef(parsed.requestedRef);
47
148
  const resolved = await resolveRegistryArtifact(parsed);
48
149
  const syncedAt = (options?.now ?? new Date()).toISOString();
150
+ if (options?.writable && options.writableRoot) {
151
+ return syncExistingWritableCheckout(parsed, resolved, options.writableRoot, syncedAt, options.writableRequiredRoots);
152
+ }
49
153
  const cacheRootDir = options?.cacheRootDir ?? getRegistryCacheDir();
50
- const cacheDir = buildInstallCacheDir(cacheRootDir, parsed.source, parsed.id, resolved.resolvedRevision);
154
+ const cacheDir = buildInstallCacheDir(cacheRootDir, parsed.source, parsed.id, options?.writable ? "writable" : resolved.resolvedRevision);
51
155
  const cloneDir = path.join(cacheDir, "clone");
52
156
  const extractedDir = path.join(cacheDir, "extracted");
53
- // Cache hit
54
- if (!options?.force && isDirectory(extractedDir)) {
157
+ // Cache hit. Writable installs must remain real checkouts so every mutation
158
+ // can be committed; an older extracted snapshot is not eligible.
159
+ if (isDirectory(extractedDir) && (!options?.writable || isDirectory(path.join(extractedDir, ".git")))) {
160
+ if (options?.writable) {
161
+ const provisionalBundleRoot = detectStashRoot(extractedDir);
162
+ const installRoot = applyAkmIncludeConfig(provisionalBundleRoot, cacheDir, extractedDir) ?? provisionalBundleRoot;
163
+ if (installRoot !== provisionalBundleRoot) {
164
+ throw new UsageError("Writable Git installs do not support akm.include (package.json) filtered snapshots.");
165
+ }
166
+ return syncExistingWritableCheckout(parsed, resolved, detectStashRoot(installRoot), syncedAt, options.writableRequiredRoots);
167
+ }
55
168
  try {
56
- const provisionalKitRoot = detectStashRoot(extractedDir);
57
- const installRoot = applyAkmIncludeConfig(provisionalKitRoot, cacheDir, extractedDir) ?? provisionalKitRoot;
169
+ if (options?.force) {
170
+ throw new Error("refresh read-only snapshot");
171
+ }
172
+ const provisionalBundleRoot = detectStashRoot(extractedDir);
173
+ const installRoot = applyAkmIncludeConfig(provisionalBundleRoot, cacheDir, extractedDir) ?? provisionalBundleRoot;
58
174
  const stashRoot = detectStashRoot(installRoot);
59
175
  if (stashRoot) {
60
176
  return {
@@ -72,20 +188,20 @@ async function doSyncGit(parsed, options) {
72
188
  };
73
189
  }
74
190
  }
75
- catch {
191
+ catch (error) {
76
192
  // Cache invalid, re-clone
77
193
  }
78
194
  }
195
+ const cacheExisted = fs.existsSync(cacheDir);
79
196
  fs.mkdirSync(cacheDir, { recursive: true });
80
- // Validate URL and ref before passing to git to prevent command injection
81
- validateGitUrl(parsed.url);
82
- if (parsed.requestedRef)
83
- validateGitRef(parsed.requestedRef);
84
- let provisionalKitRoot;
197
+ fs.rmSync(cloneDir, { recursive: true, force: true });
198
+ let provisionalBundleRoot;
85
199
  let installRoot;
86
200
  let stashRoot;
87
201
  try {
88
- const cloneArgs = ["clone", "--depth", "1"];
202
+ const cloneArgs = ["clone"];
203
+ if (!options?.writable)
204
+ cloneArgs.push("--depth", "1");
89
205
  if (parsed.requestedRef) {
90
206
  cloneArgs.push("--branch", parsed.requestedRef);
91
207
  }
@@ -94,20 +210,40 @@ async function doSyncGit(parsed, options) {
94
210
  if (cloneResult.status !== 0) {
95
211
  throw new Error(classifyCloneFailure(parsed.url, cloneResult.stderr, cloneResult.error));
96
212
  }
97
- // Copy contents to extracted dir without .git
98
- fs.mkdirSync(extractedDir, { recursive: true });
99
- copyDirectoryContents(cloneDir, extractedDir);
100
- // Clean up the clone dir
101
- fs.rmSync(cloneDir, { recursive: true, force: true });
102
- provisionalKitRoot = detectStashRoot(extractedDir);
103
- installRoot = applyAkmIncludeConfig(provisionalKitRoot, cacheDir, extractedDir) ?? provisionalKitRoot;
213
+ // R-011: `resolved.resolvedRevision` was resolved via a SEPARATE
214
+ // `git ls-remote` round-trip before this clone ran (resolveGitArtifact /
215
+ // resolveGithubArtifact in registry/resolve.ts) and was never checked
216
+ // against what actually got cloned. Verify it now, while `.git` still
217
+ // exists (the read-only branch below strips it).
218
+ verifyClonedRevision(cloneDir, parsed.url, resolved.resolvedRevision);
219
+ if (options?.writable) {
220
+ const branch = runGit(["-C", cloneDir, "branch", "--show-current"]);
221
+ if (branch.status !== 0 || !branch.stdout.trim()) {
222
+ throw new UsageError("Writable Git installs require a branch ref; tags and detached revisions are read-only.");
223
+ }
224
+ const stagedRoot = detectStashRoot(cloneDir);
225
+ if (applyAkmIncludeConfig(stagedRoot, cacheDir, cloneDir)) {
226
+ throw new UsageError("Writable Git installs do not support akm.include (package.json) filtered snapshots.");
227
+ }
228
+ replaceDirectory(cloneDir, extractedDir);
229
+ }
230
+ else {
231
+ // Read-only installs are immutable snapshots and do not retain Git metadata.
232
+ fs.rmSync(path.join(cloneDir, ".git"), { recursive: true, force: true });
233
+ replaceDirectory(cloneDir, extractedDir);
234
+ }
235
+ provisionalBundleRoot = detectStashRoot(extractedDir);
236
+ installRoot = applyAkmIncludeConfig(provisionalBundleRoot, cacheDir, extractedDir) ?? provisionalBundleRoot;
237
+ if (options?.writable && installRoot !== provisionalBundleRoot) {
238
+ throw new UsageError("Writable Git installs do not support akm.include (package.json) filtered snapshots.");
239
+ }
104
240
  stashRoot = detectStashRoot(installRoot);
105
241
  }
106
242
  catch (err) {
107
- // Clean up the cache directory so stale or partially-cloned artifacts
108
- // don't cause false cache hits on the next install attempt.
243
+ fs.rmSync(cloneDir, { recursive: true, force: true });
109
244
  try {
110
- fs.rmSync(cacheDir, { recursive: true, force: true });
245
+ if (!cacheExisted)
246
+ fs.rmSync(cacheDir, { recursive: true, force: true });
111
247
  }
112
248
  catch {
113
249
  /* best-effort */
@@ -128,12 +264,123 @@ async function doSyncGit(parsed, options) {
128
264
  syncedAt,
129
265
  };
130
266
  }
267
+ export function syncExistingWritableCheckout(parsed, resolved, contentRoot, syncedAt, requiredRoots = []) {
268
+ const root = path.resolve(contentRoot);
269
+ const repoResult = runGit(["-C", root, "rev-parse", "--show-toplevel"]);
270
+ if (repoResult.status !== 0 || !repoResult.stdout.trim()) {
271
+ throw new UsageError(`Writable Git install at ${root} is not a checkout; refusing to replace it because it may contain local work.`);
272
+ }
273
+ const repoDir = path.resolve(repoResult.stdout.trim());
274
+ if (!isWithin(root, repoDir)) {
275
+ throw new UsageError(`Writable Git content root ${root} resolves outside its checkout at ${repoDir}.`);
276
+ }
277
+ const remote = runGit(["-C", repoDir, "remote", "get-url", "origin"]);
278
+ if (remote.status !== 0 || normalizeRemoteUrl(remote.stdout) !== normalizeRemoteUrl(parsed.url)) {
279
+ throw new UsageError(`Writable Git install at ${root} points at a different origin; refusing to update or replace the checkout.`);
280
+ }
281
+ const status = runGit(["-C", repoDir, "status", "--porcelain"]);
282
+ if (status.status !== 0 || status.stdout.trim()) {
283
+ throw new UsageError(`Writable Git install at ${root} has uncommitted changes; commit or discard them before update.`);
284
+ }
285
+ if (parsed.requestedRef) {
286
+ const branch = runGit(["-C", repoDir, "branch", "--show-current"]);
287
+ const expectedBranch = parsed.requestedRef.replace(/^refs\/heads\//, "");
288
+ if (branch.status !== 0 || !branch.stdout.trim() || branch.stdout.trim() !== expectedBranch) {
289
+ throw new UsageError(`Writable Git install at ${root} is checked out on a different branch than requested ref "${parsed.requestedRef}".`);
290
+ }
291
+ }
292
+ const shallow = runGit(["-C", repoDir, "rev-parse", "--is-shallow-repository"]);
293
+ const fetchArgs = ["-C", repoDir, "fetch", "--prune", "--tags"];
294
+ if (shallow.status === 0 && shallow.stdout.trim() === "true")
295
+ fetchArgs.push("--unshallow");
296
+ fetchArgs.push("origin");
297
+ if (parsed.requestedRef)
298
+ fetchArgs.push(parsed.requestedRef);
299
+ const fetch = runGit(fetchArgs, { timeout: 120_000 });
300
+ if (fetch.status !== 0) {
301
+ throw new UsageError(`Writable Git install at ${root} could not fetch its expected origin; local work was preserved. ${fetch.stderr.trim()}`);
302
+ }
303
+ let targetRevision = resolved.resolvedRevision;
304
+ if (targetRevision) {
305
+ const resolvedTarget = runGit(["-C", repoDir, "rev-parse", "--verify", `${targetRevision}^{commit}`]);
306
+ if (resolvedTarget.status === 0)
307
+ targetRevision = resolvedTarget.stdout.trim();
308
+ else
309
+ targetRevision = undefined;
310
+ }
311
+ if (!targetRevision) {
312
+ const fallbackTarget = runGit([
313
+ "-C",
314
+ repoDir,
315
+ "rev-parse",
316
+ "--verify",
317
+ parsed.requestedRef ? "FETCH_HEAD" : "@{u}",
318
+ ]);
319
+ if (fallbackTarget.status !== 0 || !fallbackTarget.stdout.trim()) {
320
+ throw new UsageError(`Writable Git install at ${root} has no verifiable upstream revision.`);
321
+ }
322
+ targetRevision = fallbackTarget.stdout.trim();
323
+ }
324
+ const relation = gitRelation(repoDir, targetRevision);
325
+ if (relation.ahead > 0) {
326
+ throw new UsageError(`Writable Git install at ${root} has local commits that are not in the requested upstream revision; push or reconcile them before update.`);
327
+ }
328
+ assertNoIgnoredPathOverwrite(repoDir, targetRevision);
329
+ const rootsToPreserve = [...new Set([root, ...requiredRoots.map((candidate) => path.resolve(candidate))])];
330
+ for (const requiredRoot of rootsToPreserve) {
331
+ if (!isWithin(requiredRoot, repoDir)) {
332
+ throw new UsageError(`Configured Git component root ${requiredRoot} resolves outside ${repoDir}.`);
333
+ }
334
+ const relative = path.relative(repoDir, requiredRoot).replaceAll(path.sep, "/");
335
+ if (!relative)
336
+ continue;
337
+ const tree = runGit(["-C", repoDir, "ls-tree", "-d", "-z", "--name-only", targetRevision, "--", relative]);
338
+ const names = tree.stdout.split("\0").filter(Boolean);
339
+ if (tree.status !== 0 || !names.includes(relative)) {
340
+ throw new UsageError(`Writable Git update would remove configured content root ${requiredRoot}; the existing checkout was left unchanged.`);
341
+ }
342
+ }
343
+ if (relation.behind > 0) {
344
+ const statusBeforeMerge = runGit(["-C", repoDir, "status", "--porcelain"]);
345
+ if (statusBeforeMerge.status !== 0 || statusBeforeMerge.stdout.trim()) {
346
+ throw new UsageError(`Writable Git install at ${root} changed while its update was prepared; local work was preserved.`);
347
+ }
348
+ assertNoIgnoredPathOverwrite(repoDir, targetRevision);
349
+ const merge = runGit(["-C", repoDir, "merge", "--ff-only", "--no-overwrite-ignore", targetRevision], {
350
+ timeout: 120_000,
351
+ });
352
+ if (merge.status !== 0) {
353
+ throw new UsageError(`Writable Git install at ${root} cannot fast-forward; local commits were preserved. ${merge.stderr.trim()}`);
354
+ }
355
+ }
356
+ for (const requiredRoot of rootsToPreserve) {
357
+ if (!isDirectory(requiredRoot)) {
358
+ throw new UsageError(`Writable Git update did not preserve configured content root ${requiredRoot}.`);
359
+ }
360
+ }
361
+ const head = runGit(["-C", repoDir, "rev-parse", "HEAD"]);
362
+ return {
363
+ id: resolved.id,
364
+ source: resolved.source,
365
+ ref: resolved.ref,
366
+ artifactUrl: resolved.artifactUrl,
367
+ resolvedVersion: resolved.resolvedVersion,
368
+ resolvedRevision: head.status === 0 ? head.stdout.trim() : targetRevision,
369
+ contentDir: root,
370
+ cacheDir: repoDir,
371
+ extractedDir: repoDir,
372
+ writable: true,
373
+ syncedAt,
374
+ };
375
+ }
131
376
  export function cloneRepo(cloneUrl, ref, destDir, writable = false) {
132
377
  // Stage the clone into a sibling temp dir so that a failed clone never
133
378
  // destroys a previously-valid destDir (e.g. when the remote is temporarily
134
379
  // unreachable and we have a valid cached copy).
135
380
  const tmpDir = `${destDir}.tmp-${randomBytes(4).toString("hex")}`;
136
- const args = ["clone", "--depth", "1"];
381
+ const args = ["clone"];
382
+ if (!writable)
383
+ args.push("--depth", "1");
137
384
  if (ref)
138
385
  args.push("--branch", ref);
139
386
  args.push(cloneUrl, tmpDir);
@@ -150,10 +397,7 @@ export function cloneRepo(cloneUrl, ref, destDir, writable = false) {
150
397
  if (fs.existsSync(gitDir))
151
398
  fs.rmSync(gitDir, { recursive: true, force: true });
152
399
  }
153
- // Swap: remove the old destDir (if any) then atomically rename tmpDir into place.
154
- if (fs.existsSync(destDir))
155
- fs.rmSync(destDir, { recursive: true, force: true });
156
- fs.renameSync(tmpDir, destDir);
400
+ replaceDirectory(tmpDir, destDir);
157
401
  }
158
402
  catch (err) {
159
403
  // Post-clone steps failed — clean up the temp dir to avoid orphaned dirs.
@@ -164,7 +408,7 @@ export function cloneRepo(cloneUrl, ref, destDir, writable = false) {
164
408
  // ── Clone-failure classification (#487) ─────────────────────────────────────
165
409
  /**
166
410
  * Translate git's stderr into an actionable message. Without this, a user
167
- * who passes a nonexistent or private repo to `akm add` sees:
411
+ * who passes a nonexistent or private repo to `akm bundle add` sees:
168
412
  *
169
413
  * "could not read Username for 'https://github.com': No such device or
170
414
  * address"