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
@@ -19,24 +19,22 @@
19
19
  import { spawnSync } from "node:child_process";
20
20
  import fs from "node:fs";
21
21
  import path from "node:path";
22
+ import { getParsedInvocation } from "../../cli/invocation.js";
22
23
  import { getStringArg } from "../../cli/parse-args.js";
23
24
  import { defineGroupCommand, defineJsonCommand, output } from "../../cli/shared.js";
24
- import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../../core/asset/asset-create.js";
25
- import { deriveCanonicalAssetName, resolveAssetPathFromName } from "../../core/asset/asset-spec.js";
26
- import { isWithin, writeFileAtomic } from "../../core/common.js";
25
+ import { deriveCanonicalAssetName } from "../../core/asset/asset-placement.js";
26
+ import { writeFileAtomic } from "../../core/common.js";
27
27
  import { loadConfig } from "../../core/config/config.js";
28
- import { findEnvSource, makeEnvRef, parseEnvRef, resolveEnvPath } from "../../core/env-secret-ref.js";
28
+ import { makeEnvRef, resolveEnvPath, resolveEnvWriteTarget, withEnvSecretWrite } from "../../core/env-secret-ref.js";
29
29
  import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
30
- import { appendEvent } from "../../core/events.js";
31
- import { isQuiet } from "../../core/warn.js";
32
30
  import { resolveSourceEntries } from "../../indexer/search/search-source.js";
33
- import { parseFlagValue } from "../../output/context.js";
34
31
  import { readStdin } from "../../runtime.js";
35
32
  import { buildChildEnv } from "./child-env.js";
33
+ import { sensitiveMarkerPath } from "./marker-path.js";
36
34
  /**
37
35
  * Walk each stash's env files and return one entry per `.env` file, using the
38
36
  * env asset spec's canonical-name logic (e.g. `env/team/prod.env` →
39
- * `env:team/prod`, `env/team/.env` → `env:team/default`).
37
+ * `env/team/prod`, `env/team/.env` → `env/team/default`).
40
38
  */
41
39
  function listEnvsRecursive(listKeysFn) {
42
40
  const result = [];
@@ -59,7 +57,7 @@ function listEnvsRecursive(listKeysFn) {
59
57
  if (!canonical)
60
58
  continue;
61
59
  // Skip sensitive envs: a sibling .sensitive marker file suppresses listing.
62
- const markerPath = full.replace(/\.env$/, ".sensitive");
60
+ const markerPath = sensitiveMarkerPath(full, "env");
63
61
  if (fs.existsSync(markerPath))
64
62
  continue;
65
63
  const { keys } = listKeysFn(full);
@@ -71,7 +69,7 @@ function listEnvsRecursive(listKeysFn) {
71
69
  return result;
72
70
  }
73
71
  const envListCommand = defineJsonCommand({
74
- meta: { name: "list", description: "List all env files across all stashes with their key names (no values)" },
72
+ meta: { name: "list", description: "List all env files across all bundles with their key names (no values)" },
75
73
  async run() {
76
74
  const { listKeys } = await import("./env.js");
77
75
  output("env-list", { envs: listEnvsRecursive(listKeys) });
@@ -99,31 +97,29 @@ const envCreateCommand = defineJsonCommand({
99
97
  description: "Exclude this env file from env list output and the search index",
100
98
  default: false,
101
99
  },
100
+ target: {
101
+ type: "string",
102
+ description: "Override the write destination. Accepts a source name from your config; falls back to defaultWriteTarget then the working bundle.",
103
+ },
102
104
  },
103
105
  async run({ args }) {
104
106
  const { createEnv, writeEnv } = await import("./env.js");
105
- // `create` always targets env/, never the frozen vaults/ copy.
106
- const parsed = parseEnvRef(args.name);
107
- // `name` is flat; subdirectory placement is `--path`'s job.
108
- assertFlatAssetName(parsed.name);
109
- parsed.name = combineCreatePath(normalizeCreateSubPath(getStringArg(args, "path")), parsed.name);
110
- const source = findEnvSource(parsed.origin);
111
- const envRoot = path.join(source.path, "env");
112
- const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
113
- if (!isWithin(absPath, envRoot)) {
114
- throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
115
- }
107
+ // `create` always targets env/, never the frozen vaults/ copy. `--path` is
108
+ // the subdirectory; `--target` selects the writable destination source.
109
+ const { name, absPath, target, ref } = resolveEnvWriteTarget(args.name, args.target, {
110
+ subPath: getStringArg(args, "path"),
111
+ });
116
112
  const fromFile = args["from-file"];
117
113
  const fromStdin = args["from-stdin"] === true;
118
114
  if (fromFile !== undefined && fromStdin) {
119
115
  throw new UsageError("Pass only one of --from-file or --from-stdin.", "INVALID_FLAG_VALUE");
120
116
  }
117
+ let content;
121
118
  if (fromFile !== undefined || fromStdin) {
122
119
  // Ingest path: never silently clobber an existing env file.
123
120
  if (fs.existsSync(absPath)) {
124
- throw new UsageError(`Env "${makeEnvRef(parsed.name, source)}" already exists. Remove it first (\`akm env remove\`) or edit the file directly.`, "RESOURCE_ALREADY_EXISTS");
121
+ throw new UsageError(`Env "${ref}" already exists. Remove it first (\`akm env remove\`) or edit the file directly.`, "RESOURCE_ALREADY_EXISTS");
125
122
  }
126
- let content;
127
123
  if (fromFile !== undefined) {
128
124
  if (!fs.existsSync(fromFile)) {
129
125
  throw new NotFoundError(`Source file not found: ${fromFile}`, "FILE_NOT_FOUND");
@@ -135,18 +131,24 @@ const envCreateCommand = defineJsonCommand({
135
131
  const buf = await readStdin(MAX_ENV_BYTES, () => new UsageError("Env file exceeds 1 MB limit.", "INVALID_FLAG_VALUE"));
136
132
  content = buf.toString("utf8");
137
133
  }
138
- writeEnv(absPath, content);
139
- }
140
- else {
141
- createEnv(absPath);
142
134
  }
135
+ const written = [absPath];
136
+ const markerPath = sensitiveMarkerPath(absPath, "env");
143
137
  if (args.sensitive) {
144
- const markerPath = absPath.replace(/\.env$/, ".sensitive");
145
- if (!fs.existsSync(markerPath)) {
146
- fs.writeFileSync(markerPath, "", { mode: 0o600 });
147
- }
138
+ written.push(markerPath);
148
139
  }
149
- output("env-create", { ref: makeEnvRef(parsed.name, source) });
140
+ withEnvSecretWrite(target, { type: "env", name }, "Update", written, () => {
141
+ if (content !== undefined)
142
+ writeEnv(absPath, content);
143
+ else
144
+ createEnv(absPath);
145
+ if (args.sensitive) {
146
+ if (!fs.existsSync(markerPath)) {
147
+ writeFileAtomic(markerPath, "", 0o600);
148
+ }
149
+ }
150
+ });
151
+ output("env-create", { ref });
150
152
  },
151
153
  });
152
154
  const envPathCommand = defineJsonCommand({
@@ -170,6 +172,22 @@ const envPathCommand = defineJsonCommand({
170
172
  process.stderr.write(`warning: this is the raw file path. Do NOT \`source\` it (shell substitutions in the file would execute).\n` +
171
173
  ` To inject values run: akm env run ${args.ref} -- <command>\n`);
172
174
  }
175
+ // F3/B3: this stdout write IS the payload — a bare absolute path for
176
+ // shell substitution (`$(akm env path <ref>)`, Docker `_FILE` /
177
+ // `--env-file`) — not a field inside a result envelope. `env path` is
178
+ // now declared format-exempt (src/output/format-exempt.ts, same
179
+ // classification as `env run`/`secret run`/`help`), so `--format`
180
+ // WARNS rather than doing anything to this write (src/cli.ts's startup
181
+ // `isFormatExemptCommand` check). An earlier version of this fix routed
182
+ // this through `output()` with a `{ path }` envelope so `--format`
183
+ // "worked" — but the CLI's process-wide default format is `json`, so a
184
+ // bare `akm env path <ref>` (exactly how `$(akm env path foo)` is
185
+ // written, with no explicit `--format`) started emitting
186
+ // `{"path":"..."}` instead of the raw path, breaking every existing
187
+ // shell substitution silently. Declaring the exemption is the correct
188
+ // fix: it keeps this byte-identical to history and makes the
189
+ // already-broken combination (`--format` + this command) loud instead
190
+ // of silent, per STABILITY.md's promise for exempt commands.
173
191
  process.stdout.write(`${absPath}\n`);
174
192
  },
175
193
  });
@@ -205,11 +223,10 @@ const envExportCommand = defineJsonCommand({
205
223
  * for process-hijacking variables.
206
224
  */
207
225
  async function runEnvInjected(target, opts) {
208
- const dashIndex = process.argv.indexOf("--");
209
- if (dashIndex < 0 || dashIndex === process.argv.length - 1) {
226
+ const command = getParsedInvocation().passthroughArgs();
227
+ if (command.length === 0) {
210
228
  throw new UsageError("Missing command. Usage: akm env run <ref> -- <command>");
211
229
  }
212
- const command = process.argv.slice(dashIndex + 1);
213
230
  const { name, absPath, source } = resolveEnvPath(target);
214
231
  if (!fs.existsSync(absPath)) {
215
232
  // Help users who reach for the removed single-key `ref/KEY` form.
@@ -226,70 +243,20 @@ async function runEnvInjected(target, opts) {
226
243
  }
227
244
  if (baseExists) {
228
245
  throw new UsageError(`'akm env run' injects the whole file; the single-key '<ref>/${maybeKey}' form was removed.\n` +
229
- ` For one value use a secret: \`akm secret run secret:${maybeKey} ${maybeKey} -- <command>\`.`, "INVALID_FLAG_VALUE");
246
+ ` For one value use a secret: \`akm secret run secrets/${maybeKey} ${maybeKey} -- <command>\`.`, "INVALID_FLAG_VALUE");
230
247
  }
231
248
  }
232
249
  }
233
250
  throw new NotFoundError(`Env not found: ${makeEnvRef(name, source)}`);
234
251
  }
235
- const { loadEnv } = await import("./env.js");
236
- const allValues = loadEnv(absPath);
237
- // Value-safe key filtering (--only / --except operate on key NAMES only).
238
- let envValues = allValues;
239
- if (opts.only && opts.except) {
240
- throw new UsageError("Pass only one of --only or --except.", "INVALID_FLAG_VALUE");
241
- }
242
- if (opts.only) {
243
- const wanted = new Set(opts.only);
244
- const missing = opts.only.filter((k) => !(k in allValues));
245
- if (missing.length > 0) {
246
- process.stderr.write(`warning: --only key(s) not present in ${makeEnvRef(name, source)}: ${missing.join(", ")}\n`);
247
- }
248
- envValues = Object.fromEntries(Object.entries(allValues).filter(([k]) => wanted.has(k)));
249
- }
250
- else if (opts.except) {
251
- const excluded = new Set(opts.except);
252
- envValues = Object.fromEntries(Object.entries(allValues).filter(([k]) => !excluded.has(k)));
253
- }
254
- // Substitute `${secret:NAME}` tokens in values with the value of the sibling
255
- // secret asset in the SAME stash. The lookup is injected so commands/env.ts
256
- // keeps its narrow dependency surface; we resolve each name against this env's
257
- // own `source`. A missing secret is a hard error — inject NOTHING (no partial
258
- // injection). Resolved values are never logged or printed.
259
- const { resolveSecretTokens } = await import("./env.js");
260
- const { readValue } = await import("./secret.js");
261
- const secretsRoot = path.join(source.path, "secrets");
262
- const resolveSecret = (secretName) => {
263
- const secretPath = resolveAssetPathFromName("secret", secretsRoot, secretName);
264
- // Defense-in-depth: ensure the resolved path stays inside the secrets dir.
265
- if (!isWithin(secretPath, secretsRoot)) {
266
- throw new UsageError(`Secret name "${secretName}" escapes the secrets directory.`);
267
- }
268
- if (!fs.existsSync(secretPath))
269
- return undefined;
270
- // Match `secret run`: read utf8, do not trim (stay consistent with that path).
271
- return readValue(secretPath).toString("utf8");
272
- };
273
- const { values: substituted, missing } = resolveSecretTokens(envValues, resolveSecret);
274
- if (missing.length > 0) {
275
- const envRef = makeEnvRef(name, source);
276
- throw new NotFoundError(`Env "${envRef}" references secret(s) not found in its stash: ${missing.map((n) => `secret:${n}`).join(", ")}. Nothing was injected.`, "FILE_NOT_FOUND", `Create the missing secret, e.g. \`akm secret set secret:${missing[0]}\`.`);
277
- }
278
- envValues = substituted;
279
- const keys = Object.keys(envValues);
280
- // Scan injected keys for known process-hijacking variables (LD_PRELOAD,
281
- // PATH, ...). Block for third-party-sourced stashes (origin has a registryId);
282
- // warn for the operator's own first-party stash, where they own the file.
283
- const { isDangerousEnvKey } = await import("../lint/env-key-rules.js");
284
- const dangerous = keys.filter(isDangerousEnvKey);
285
- if (dangerous.length > 0) {
286
- const detail = `Env "${makeEnvRef(name, source)}" injects process-hijacking variable(s): ${dangerous.join(", ")}.`;
287
- if (source.registryId) {
288
- throw new UsageError(`Refusing to inject env from a third-party stash. ${detail}\n` +
289
- ` Review the file, then copy the values into a first-party env if you trust them.`, "INVALID_FLAG_VALUE");
290
- }
291
- process.stderr.write(`warning: ${detail} Injecting anyway (first-party stash).\n`);
292
- }
252
+ // Load → filter → secret-substitute → dangerous-key policy → keys-only
253
+ // audit event. Shared with the workflow engine's per-unit env bindings —
254
+ // see env-binding.ts for the extracted core and its safety invariants.
255
+ const { resolveEnvBinding } = await import("./env-binding.js");
256
+ const { values: envValues } = resolveEnvBinding(target, {
257
+ only: opts.only,
258
+ except: opts.except,
259
+ });
293
260
  const mergedEnv = buildChildEnv(process.env, {
294
261
  clean: opts.clean === true,
295
262
  inherit: opts.inherit ?? [],
@@ -297,12 +264,6 @@ async function runEnvInjected(target, opts) {
297
264
  for (const [envKey, envValue] of Object.entries(envValues)) {
298
265
  mergedEnv[envKey] = envValue;
299
266
  }
300
- // Audit trail: keys only, never values.
301
- appendEvent({
302
- eventType: "env_access",
303
- ref: makeEnvRef(name, source),
304
- metadata: { keys },
305
- });
306
267
  const result = spawnSync(command[0], command.slice(1), {
307
268
  stdio: "inherit",
308
269
  env: mergedEnv,
@@ -320,7 +281,15 @@ async function runEnvInjected(target, opts) {
320
281
  }
321
282
  throw err;
322
283
  }
323
- process.exit(result.status ?? 0);
284
+ // R-067: was `process.exit(result.status ?? 0)`, which terminates the
285
+ // process synchronously and skips the `finally { await
286
+ // disposeDispatchResources(); }` block in src/cli.ts's `runCommand` — even
287
+ // on the success path, since this call was unconditional. Setting
288
+ // `process.exitCode` and returning lets cleanup run while still exiting
289
+ // with the child's exact status once the event loop drains, matching the
290
+ // pattern `emitJsonError` (src/cli/shared.ts) already established.
291
+ process.exitCode = result.status ?? 0;
292
+ return;
324
293
  }
325
294
  /** Parse a comma/space-separated key list flag into a trimmed, non-empty array. */
326
295
  function parseKeyListFlag(raw) {
@@ -337,7 +306,7 @@ const envRunCommand = defineJsonCommand({
337
306
  name: "run",
338
307
  description:
339
308
  // biome-ignore lint/suspicious/noTemplateCurlyInString: literal `${secret:NAME}` token syntax documented for users, not interpolation
340
- "Run a command with the env file injected into its environment: `akm env run <ref> -- <command>`. Use `-- $SHELL` for an interactive session. Restrict which variables are injected with --only / --except. Values may embed `${secret:NAME}` tokens, replaced at run time with the sibling `secret:NAME` value from the same stash. Pass --clean to start the child with a minimal inherited environment instead of the full parent environment.",
309
+ "Run a command with the env file injected into its environment: `akm env run <ref> -- <command>`. Use `-- $SHELL` for an interactive session. Restrict which variables are injected with --only / --except. Values may embed `${secret:NAME}` tokens, replaced at run time with the sibling `${secret:NAME}` value from the same bundle. Pass --clean to start the child with a minimal inherited environment instead of the full parent environment.",
341
310
  },
342
311
  args: {
343
312
  target: { type: "positional", description: "Env ref", required: true },
@@ -370,15 +339,13 @@ const envRemoveCommand = defineJsonCommand({
370
339
  args: {
371
340
  ref: { type: "positional", description: "Env ref", required: true },
372
341
  yes: { type: "boolean", alias: "y", description: "Skip confirmation prompt", default: false },
342
+ target: {
343
+ type: "string",
344
+ description: "Override the write destination. Accepts a source name from your config; falls back to defaultWriteTarget then the working bundle.",
345
+ },
373
346
  },
374
347
  async run({ args }) {
375
- const parsed = parseEnvRef(args.ref);
376
- const source = findEnvSource(parsed.origin);
377
- const envRoot = path.join(source.path, "env");
378
- const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
379
- if (!isWithin(absPath, envRoot)) {
380
- throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
381
- }
348
+ const { name, absPath, target, ref } = resolveEnvWriteTarget(args.ref, args.target);
382
349
  const { confirmDestructive } = await import("../../cli/confirm.js");
383
350
  const confirmed = await confirmDestructive(`Remove env "${args.ref}"? This cannot be undone.`, {
384
351
  yes: args.yes === true,
@@ -388,122 +355,18 @@ const envRemoveCommand = defineJsonCommand({
388
355
  return;
389
356
  }
390
357
  if (!fs.existsSync(absPath)) {
391
- throw new NotFoundError(`Env not found: ${makeEnvRef(parsed.name, source)}`);
358
+ throw new NotFoundError(`Env not found: ${ref}`);
392
359
  }
393
360
  const { removeEnv } = await import("./env.js");
394
- const removed = removeEnv(absPath);
395
- output("env-remove", { ref: makeEnvRef(parsed.name, source), removed });
396
- },
397
- });
398
- const envSetCommand = defineJsonCommand({
399
- meta: {
400
- name: "set",
401
- description: "Set (create or update) a single KEY in an env file: `akm env set <ref> <KEY>`. The value is read from stdin by default (never via argv); use --from-env <VAR> or --from-file <path>. Preserves existing comments and key order; the value is never printed. Creates the env file if it does not exist.",
402
- },
403
- args: {
404
- ref: { type: "positional", description: "Env ref (e.g. env:prod or just prod)", required: true },
405
- key: { type: "positional", description: "Key name to set (e.g. API_URL)", required: true },
406
- "from-env": { type: "string", description: "Read the value from the named environment variable" },
407
- "from-file": { type: "string", description: "Read the value from this file" },
408
- },
409
- async run({ args }) {
410
- const parsed = parseEnvRef(args.ref);
411
- const source = findEnvSource(parsed.origin);
412
- const envRoot = path.join(source.path, "env");
413
- const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
414
- if (!isWithin(absPath, envRoot)) {
415
- throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
416
- }
417
- const key = String(args.key);
418
- const { ENV_KEY_RE, setEnvKey } = await import("./env.js");
419
- if (!ENV_KEY_RE.test(key)) {
420
- throw new UsageError(`Invalid env key "${key}". Keys match [A-Za-z_][A-Za-z0-9_]*.`, "INVALID_FLAG_VALUE");
421
- }
422
- const fromEnv = args["from-env"];
423
- const fromFile = args["from-file"];
424
- if (fromEnv !== undefined && fromFile !== undefined) {
425
- throw new UsageError("Pass only one of --from-file or --from-env (or use stdin).", "INVALID_FLAG_VALUE");
426
- }
427
- const MAX_ENV_VALUE_BYTES = 1024 * 1024; // 1 MB
428
- let value;
429
- if (fromFile !== undefined) {
430
- if (!fs.existsSync(fromFile)) {
431
- throw new NotFoundError(`File not found: ${fromFile}`, "FILE_NOT_FOUND");
432
- }
433
- const buf = fs.readFileSync(fromFile);
434
- if (buf.byteLength > MAX_ENV_VALUE_BYTES)
435
- throw new UsageError("Value exceeds the 1 MB limit.");
436
- value = buf.toString("utf8");
437
- }
438
- else if (fromEnv !== undefined) {
439
- const v = process.env[fromEnv];
440
- if (v === undefined) {
441
- throw new UsageError(`Environment variable "${fromEnv}" is not set.`, "INVALID_FLAG_VALUE");
442
- }
443
- value = v;
444
- }
445
- else {
446
- const buf = await readStdin(MAX_ENV_VALUE_BYTES, () => new UsageError("Value exceeds the 1 MB limit."));
447
- // Strip a single trailing newline so `echo "$VAL" | akm env set` is exact.
448
- value = buf.toString("utf8").replace(/\n$/, "");
449
- }
450
- setEnvKey(absPath, key, value);
451
- // Warn (never block) on process-hijacking key names, matching the env-run audit.
452
- const { isDangerousEnvKey } = await import("../lint/env-key-rules.js");
453
- if (isDangerousEnvKey(key) && !isQuiet()) {
454
- process.stderr.write(`warning: "${key}" can influence process execution when this env is loaded via 'akm env run'.\n`);
455
- }
456
- output("env-set", { ref: makeEnvRef(parsed.name, source), key });
457
- },
458
- });
459
- const envUnsetCommand = defineJsonCommand({
460
- meta: {
461
- name: "unset",
462
- description: "Remove one or more KEYs from an env file: `akm env unset <ref> <KEY...>`. Preserves other keys and comments. To remove the whole file, use `akm env remove`.",
463
- },
464
- args: {
465
- ref: { type: "positional", description: "Env ref (e.g. env:prod or just prod)", required: true },
466
- // `key` is read from the raw positionals (one or more) in run(); declared
467
- // non-required so citty doesn't block before we emit a structured error.
468
- key: { type: "positional", description: "Key name(s) to remove (one or more)", required: false },
469
- },
470
- async run({ args }) {
471
- const parsed = parseEnvRef(args.ref);
472
- const source = findEnvSource(parsed.origin);
473
- const envRoot = path.join(source.path, "env");
474
- const absPath = resolveAssetPathFromName("env", envRoot, parsed.name);
475
- if (!isWithin(absPath, envRoot)) {
476
- throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
477
- }
478
- if (!fs.existsSync(absPath)) {
479
- throw new NotFoundError(`Env not found: ${makeEnvRef(parsed.name, source)}`);
480
- }
481
- // citty puts every positional in `args._` (incl. the ref at [0]); the keys
482
- // are the remaining positionals. citty also mis-captures the space-separated
483
- // value of a global flag (`--format json`) as a positional, so drop any
484
- // token that is actually a global flag's value (cli.ts:1335 documents this).
485
- const globalFlagValues = new Set(["--format", "--shape", "--detail", "--scope", "--filter", "--target"]
486
- .map((flag) => parseFlagValue(process.argv, flag))
487
- .filter((v) => typeof v === "string"));
488
- const keys = (Array.isArray(args._) ? args._.map(String) : [])
489
- .slice(1)
490
- .filter((k) => !globalFlagValues.has(k));
491
- if (keys.length === 0) {
492
- throw new UsageError("Usage: akm env unset <ref> <KEY...> (one or more keys).", "MISSING_REQUIRED_ARGUMENT");
493
- }
494
- const { ENV_KEY_RE, unsetEnvKeys } = await import("./env.js");
495
- const invalid = keys.filter((k) => !ENV_KEY_RE.test(k));
496
- if (invalid.length > 0) {
497
- throw new UsageError(`Invalid env key(s): ${invalid.join(", ")}.`, "INVALID_FLAG_VALUE");
498
- }
499
- const { removed, missing } = unsetEnvKeys(absPath, keys);
500
- output("env-unset", { ref: makeEnvRef(parsed.name, source), removed, missing });
361
+ const removed = withEnvSecretWrite(target, { type: "env", name }, "Remove", [absPath, sensitiveMarkerPath(absPath, "env")], () => removeEnv(absPath));
362
+ output("env-remove", { ref, removed });
501
363
  },
502
364
  });
503
365
  export const envCommand = defineGroupCommand({
504
366
  meta: {
505
367
  name: "env",
506
- description: "Manage `.env` files — a group of related CONFIGURATION values for an app or service (URLs, flags, plus any credentials it needs), loaded together. Values may or may not be sensitive; akm protects them all the same (key names visible, values never in structured output). For a single sensitive value used on its own (an auth token, key, or cert), use `akm secret`.",
368
+ description: "Manage `.env` files — configuration values an app loads together (URLs, flags, and any credentials it needs).\n\n" +
369
+ "Values may or may not be sensitive; akm protects them all the same way — key names are visible, values never appear in structured output. For a single sensitive value used on its own (an auth token, key, or cert), use `akm secret`.",
507
370
  },
508
371
  subCommands: {
509
372
  list: envListCommand,
@@ -511,12 +374,9 @@ export const envCommand = defineGroupCommand({
511
374
  export: envExportCommand,
512
375
  run: envRunCommand,
513
376
  create: envCreateCommand,
514
- set: envSetCommand,
515
- unset: envUnsetCommand,
516
377
  remove: envRemoveCommand,
517
378
  },
518
- async defaultRun() {
519
- const { listKeys } = await import("./env.js");
520
- output("env-list", { envs: listEnvsRecursive(listKeys) });
521
- },
379
+ // No `defaultRun`: bare `akm env` is a usage error (exit 2), the canonical
380
+ // bare-group behavior — owner ruling 12. Run `akm env list` for what the
381
+ // bare form used to print.
522
382
  });