akm-cli 0.9.0-rc.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -2,7 +2,7 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * `akm tasks` — register, inspect, run, and remove scheduled task assets.
5
+ * `akm task` — register, inspect, run, and remove scheduled task assets.
6
6
  *
7
7
  * Each handler exported here is a pure function that performs the real work;
8
8
  * `src/cli.ts` wraps these in citty `defineCommand`s and shapes their return
@@ -15,18 +15,20 @@ import { assetPathForName } from "../../core/asset/asset-placement.js";
15
15
  import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
16
16
  import { isWithin, resolveStashDir } from "../../core/common.js";
17
17
  import { loadConfig } from "../../core/config/config.js";
18
+ import { IMPROVE_AUTONOMY_CONFIG_KEY, isImproveAutonomyEnabled } from "../../core/config/experimental.js";
18
19
  import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
19
20
  import { getTaskHistoryDir, getTaskLogDir } from "../../core/paths.js";
20
- import { commitWriteTargetBoundary, deleteAssetFromSource, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
21
- import { resolveAssetPath } from "../../sources/resolve.js";
21
+ import { commitWriteTargetBoundary, deleteAssetFromSource, prepareWriteTargetForMutation, resolveWriteTarget, writeAssetToSource, } from "../../core/write-source.js";
22
+ import { withEngineFallback } from "../../integrations/agent/engine-fallback.js";
22
23
  import { backendNameForPlatform, selectBackend } from "../../tasks/backends/index.js";
23
- import { findBareAkmExecutableIndex } from "../../tasks/command-executable.js";
24
24
  import { parseTaskDocument } from "../../tasks/parser.js";
25
25
  import { resolveAkmInvocation } from "../../tasks/resolve-akm-bin.js";
26
26
  import { exitCodeForStatus, INVALID_TASK_ATTEMPT_ID, readTaskHistory, recordTaskAttemptFailure, runTask, } from "../../tasks/runner.js";
27
- import { parseSchedule, SCHEDULE_SUPPORTED_SUBSET_HINT, translateToCron } from "../../tasks/schedule.js";
27
+ import { parseSchedule, SCHEDULE_SUPPORTED_SUBSET_HINT } from "../../tasks/schedule.js";
28
+ import { schedulerContextDescriptor, validateSchedulerContextDescriptor, writeSchedulerContextDescriptor, } from "../../tasks/scheduler-invocation.js";
28
29
  import { normaliseTaskId } from "../../tasks/task-id.js";
29
30
  import { validateTaskDocument } from "../../tasks/validator.js";
31
+ import { applyAutonomyGate, configuredDirectAutonomyLanes, describeGatedLanes } from "../improve/autonomy-gate.js";
30
32
  import { resolveImproveStrategy } from "../improve/improve-strategies.js";
31
33
  export async function akmTasksAdd(input, deps = {}) {
32
34
  const id = normaliseTaskId(input.id);
@@ -49,15 +51,22 @@ export async function akmTasksAdd(input, deps = {}) {
49
51
  // from `deps.backend` when present — retiring the `_setBackendsForTests` seam.
50
52
  const backend = deps.backend?.name ?? backendNameForPlatform();
51
53
  parseSchedule(input.schedule, backend);
52
- const target = resolveTaskWriteTarget();
53
- const stashDir = target.source.path;
54
+ const bundle = resolveTaskBundle(input.target, { requireWritable: true });
55
+ const writeTarget = bundle.resolved;
56
+ const stashDir = bundle.stashDir;
57
+ const installOpts = bundle.installTarget !== undefined ? { target: bundle.installTarget } : undefined;
54
58
  const typeRoot = path.join(stashDir, "tasks");
55
59
  const assetPath = assetPathForName("task", typeRoot, id);
56
60
  if (!isWithin(assetPath, typeRoot)) {
57
61
  throw new UsageError(`Resolved task path escapes the stash: "${id}".`, "PATH_ESCAPE_VIOLATION");
58
62
  }
59
- if (fs.existsSync(assetPath) && !input.force) {
60
- throw new UsageError(`Task "${id}" already exists. Pass --force to overwrite, or use \`akm tasks remove ${id}\` first.`, "RESOURCE_ALREADY_EXISTS");
63
+ // Pre-0.8.0 tasks were markdown; the 0.8.0 cutover moved them to pure YAML
64
+ // (see the tasks dir rule in src/indexer/walk/matchers.ts). A leftover
65
+ // `<id>.md` still names the same task, so creating `<id>.yml` beside it
66
+ // must collide loudly rather than silently minting a duplicate.
67
+ const legacyAssetPath = path.join(typeRoot, `${id}.md`);
68
+ if ((fs.existsSync(assetPath) || fs.existsSync(legacyAssetPath)) && !input.force) {
69
+ throw new UsageError(`Task "${id}" already exists. Pass --force to overwrite, or delete its file and run \`akm task sync\` first.`, "RESOURCE_ALREADY_EXISTS");
61
70
  }
62
71
  const yaml = renderTaskYaml({
63
72
  id,
@@ -77,9 +86,6 @@ export async function akmTasksAdd(input, deps = {}) {
77
86
  });
78
87
  const task = parseTaskDocument({ yaml, filePath: assetPath, id });
79
88
  await validateTaskDocument(task, { backend, stashDir });
80
- const obsoleteReason = obsoleteBackupTaskReason(task);
81
- if (obsoleteReason)
82
- throw new UsageError(obsoleteReason, "INVALID_FLAG_VALUE");
83
89
  const ref = taskAssetRef(id);
84
90
  const previousYaml = fs.existsSync(assetPath) ? fs.readFileSync(assetPath, "utf8") : undefined;
85
91
  let previousTask;
@@ -96,15 +102,19 @@ export async function akmTasksAdd(input, deps = {}) {
96
102
  const writeAsset = deps.writeAsset ?? writeAssetToSource;
97
103
  const deleteAsset = deps.deleteAsset ?? deleteAssetFromSource;
98
104
  const commitBoundary = deps.commitBoundary ?? commitWriteTargetBoundary;
99
- const wasInstalled = previousYaml !== undefined && (await sched.list()).some((entry) => entry.id === id);
105
+ const installedEntries = await sched.list();
106
+ assertNoForeignSchedule(installedEntries, id, bundle.installTarget);
107
+ const wasInstalled = previousYaml !== undefined && installedEntries.some((entry) => entry.id === id);
108
+ const installedEntry = installedEntries.find((entry) => entry.id === id);
109
+ const runtimeOpts = schedulerInstallOptions(installOpts, installedEntry, deps, installedEntry ? false : input.rebind === true, `create scheduler entry for task "${id}"`);
100
110
  let sourceRestoreArmed = false;
101
111
  let installSucceeded = false;
102
112
  try {
103
113
  sourceRestoreArmed = true;
104
- await writeAsset(target.source, target.config, ref, yaml);
105
- await sched.install(task);
114
+ await writeAsset(writeTarget.source, writeTarget.config, ref, yaml);
115
+ await sched.install(task, runtimeOpts);
106
116
  installSucceeded = true;
107
- commitBoundary(target, `Update tasks/${id}`);
117
+ commitBoundary(writeTarget, `Update tasks/${id}`);
108
118
  }
109
119
  catch (err) {
110
120
  const rollbackErrors = [];
@@ -113,12 +123,12 @@ export async function akmTasksAdd(input, deps = {}) {
113
123
  try {
114
124
  if (previousYaml === undefined) {
115
125
  if (fs.existsSync(assetPath)) {
116
- await deleteAsset(target.source, target.config, ref);
126
+ await deleteAsset(writeTarget.source, writeTarget.config, ref);
117
127
  sourceRestored = true;
118
128
  }
119
129
  }
120
130
  else {
121
- await restoreTaskSourceBytes(writeAsset, target.source, target.config, ref, assetPath, previousYaml);
131
+ await restoreTaskSourceBytes(writeAsset, writeTarget.source, writeTarget.config, ref, assetPath, previousYaml);
122
132
  sourceRestored = true;
123
133
  }
124
134
  }
@@ -136,7 +146,7 @@ export async function akmTasksAdd(input, deps = {}) {
136
146
  }
137
147
  else if (installSucceeded && previousTask) {
138
148
  try {
139
- await sched.install(previousTask);
149
+ await sched.install(previousTask, runtimeOpts);
140
150
  }
141
151
  catch (rollbackError) {
142
152
  rollbackErrors.push(rollbackError);
@@ -162,7 +172,7 @@ export async function akmTasksAdd(input, deps = {}) {
162
172
  }
163
173
  if (sourceRestored) {
164
174
  try {
165
- commitBoundary(target, `Restore tasks/${id}`);
175
+ commitBoundary(writeTarget, `Restore tasks/${id}`);
166
176
  }
167
177
  catch (rollbackError) {
168
178
  rollbackErrors.push(rollbackError);
@@ -178,252 +188,13 @@ export async function akmTasksAdd(input, deps = {}) {
178
188
  id,
179
189
  ref: conceptIdFromTypeName("task", id),
180
190
  path: assetPath,
181
- stashDir,
191
+ bundleDir: stashDir,
182
192
  schedule: task.schedule,
183
193
  enabled: task.enabled,
184
194
  backend,
185
195
  target: task.target,
186
196
  };
187
197
  }
188
- /**
189
- * Emit a single grouped stderr warning for legacy `.md` task files in the
190
- * tasks directory. 0.8.0 requires task definitions to be pure `.yml`; any
191
- * leftover `.md` files from 0.7.x would otherwise be silently skipped, which
192
- * makes scheduled tasks vanish without operator notice. We do NOT auto-migrate
193
- * — that is a separate workstream — but operators must see the affected files.
194
- *
195
- * `seen` is module-level so the warning is emitted at most once per process,
196
- * even when both `akm tasks list` and `akm tasks sync` are invoked in the same
197
- * akm run.
198
- */
199
- const warnedLegacyMdDirs = new Set();
200
- function warnLegacyMdTaskFiles(typeRoot) {
201
- if (warnedLegacyMdDirs.has(typeRoot))
202
- return;
203
- let mdFiles;
204
- try {
205
- mdFiles = fs.readdirSync(typeRoot).filter((f) => f.endsWith(".md"));
206
- }
207
- catch {
208
- return;
209
- }
210
- if (mdFiles.length === 0)
211
- return;
212
- warnedLegacyMdDirs.add(typeRoot);
213
- const affected = mdFiles.map((f) => `tasks/${f}`).join(", ");
214
- process.stderr.write(`WARNING: ${mdFiles.length} task file(s) use the legacy .md format and were ignored.\n` +
215
- ` AKM 0.8.0 requires tasks as pure .yml. See docs/migration/v0.7-to-v0.8.md#task-definition-files-mdfrontmatter--yml.\n` +
216
- ` Affected: ${affected}\n`);
217
- }
218
- /**
219
- * Reset the legacy `.md` task warning de-duplication state. Test-only escape
220
- * hatch — production code should never call this.
221
- */
222
- export function _resetLegacyMdTaskWarningStateForTests() {
223
- warnedLegacyMdDirs.clear();
224
- }
225
- export async function akmTasksList() {
226
- const stashDir = resolveStashDir();
227
- const typeRoot = path.join(stashDir, "tasks");
228
- if (!fs.existsSync(typeRoot))
229
- return { tasks: [], stale: [] };
230
- const entries = fs.readdirSync(typeRoot);
231
- warnLegacyMdTaskFiles(typeRoot);
232
- const files = entries.filter((f) => f.endsWith(".yml"));
233
- const tasks = [];
234
- const stale = [];
235
- for (const file of files) {
236
- const id = file.slice(0, -4);
237
- const filePath = path.join(typeRoot, file);
238
- let task;
239
- try {
240
- task = parseTaskDocument({ yaml: fs.readFileSync(filePath, "utf8"), filePath, id });
241
- }
242
- catch (err) {
243
- if (isStaleTaskError(err))
244
- stale.push(id);
245
- continue; // skip malformed files; `akm tasks show <id>` will surface the error
246
- }
247
- tasks.push({
248
- id: task.id,
249
- ref: conceptIdFromTypeName("task", task.id),
250
- path: filePath,
251
- schedule: task.schedule,
252
- enabled: task.enabled,
253
- target: task.target,
254
- name: task.name,
255
- description: task.description,
256
- when_to_use: task.when_to_use,
257
- tags: task.tags,
258
- });
259
- }
260
- if (stale.length > 0)
261
- warnStaleTaskFiles(stale);
262
- return { tasks, stale };
263
- }
264
- export async function akmTasksShow(id) {
265
- const normalised = normaliseTaskId(id);
266
- const stashDir = resolveStashDir();
267
- const typeRoot = path.join(stashDir, "tasks");
268
- if (fs.existsSync(typeRoot))
269
- warnLegacyMdTaskFiles(typeRoot);
270
- const filePath = await resolveAssetPath(stashDir, "task", normalised);
271
- const task = parseTaskDocument({
272
- yaml: fs.readFileSync(filePath, "utf8"),
273
- filePath,
274
- id: normalised,
275
- });
276
- const spec = parseSchedule(task.schedule, backendNameForPlatform());
277
- return {
278
- id: task.id,
279
- ref: conceptIdFromTypeName("task", task.id),
280
- path: filePath,
281
- schedule: task.schedule,
282
- cron: translateToCron(spec),
283
- enabled: task.enabled,
284
- target: task.target,
285
- name: task.name,
286
- description: task.description,
287
- when_to_use: task.when_to_use,
288
- tags: task.tags,
289
- };
290
- }
291
- export async function akmTasksRemove(id, deps = {}) {
292
- const normalised = normaliseTaskId(id);
293
- const target = resolveTaskWriteTarget();
294
- const stashDir = target.source.path;
295
- const typeRoot = path.join(stashDir, "tasks");
296
- if (fs.existsSync(typeRoot))
297
- warnLegacyMdTaskFiles(typeRoot);
298
- const filePath = await resolveAssetPath(stashDir, "task", normalised);
299
- const yaml = fs.readFileSync(filePath, "utf8");
300
- const ref = taskAssetRef(normalised);
301
- const sched = deps.backend ?? selectBackend();
302
- const writeAsset = deps.writeAsset ?? writeAssetToSource;
303
- const deleteAsset = deps.deleteAsset ?? deleteAssetFromSource;
304
- const commitBoundary = deps.commitBoundary ?? commitWriteTargetBoundary;
305
- const wasInstalled = (await sched.list()).some((entry) => entry.id === normalised);
306
- const previousTask = wasInstalled ? parseTaskDocument({ yaml, filePath, id: normalised }) : undefined;
307
- let uninstallAttempted = false;
308
- let deleteAttempted = false;
309
- try {
310
- uninstallAttempted = true;
311
- await sched.uninstall(normalised);
312
- deleteAttempted = true;
313
- await deleteAsset(target.source, target.config, ref);
314
- commitBoundary(target, `Remove tasks/${normalised}`);
315
- }
316
- catch (err) {
317
- const rollbackErrors = [];
318
- let sourceRestored = false;
319
- if (deleteAttempted) {
320
- try {
321
- await restoreTaskSourceBytes(writeAsset, target.source, target.config, ref, filePath, yaml);
322
- sourceRestored = true;
323
- }
324
- catch (rollbackError) {
325
- rollbackErrors.push(rollbackError);
326
- }
327
- }
328
- if (uninstallAttempted && previousTask) {
329
- try {
330
- await sched.install(previousTask);
331
- }
332
- catch (rollbackError) {
333
- rollbackErrors.push(rollbackError);
334
- }
335
- }
336
- if (sourceRestored) {
337
- try {
338
- commitBoundary(target, `Restore tasks/${normalised}`);
339
- }
340
- catch (rollbackError) {
341
- rollbackErrors.push(rollbackError);
342
- }
343
- }
344
- if (rollbackErrors.length > 0) {
345
- const message = err instanceof Error ? err.message : String(err);
346
- throw new AggregateError([err, ...rollbackErrors], `${message}; rollback for task "${normalised}" was incomplete.`);
347
- }
348
- throw err;
349
- }
350
- return { id: normalised, removed: true, backend: sched.name };
351
- }
352
- export async function akmTasksSetEnabled(id, enabled, deps = {}) {
353
- const normalised = normaliseTaskId(id);
354
- const target = resolveTaskWriteTarget();
355
- const stashDir = target.source.path;
356
- const typeRoot = path.join(stashDir, "tasks");
357
- if (fs.existsSync(typeRoot))
358
- warnLegacyMdTaskFiles(typeRoot);
359
- const filePath = await resolveAssetPath(stashDir, "task", normalised);
360
- const yaml = fs.readFileSync(filePath, "utf8");
361
- // Parse before writing so unsupported tasks are diagnosed without changing
362
- // the source file or its installed scheduler entry.
363
- const previousTask = parseTaskDocument({ yaml, filePath, id: normalised });
364
- const updated = setEnabledInYaml(yaml, enabled);
365
- const task = parseTaskDocument({ yaml: updated, filePath, id: normalised });
366
- const obsoleteReason = obsoleteBackupTaskReason(task);
367
- if (obsoleteReason)
368
- throw new UsageError(obsoleteReason, "INVALID_FLAG_VALUE");
369
- const ref = taskAssetRef(normalised);
370
- const sched = deps.backend ?? selectBackend();
371
- const writeAsset = deps.writeAsset ?? writeAssetToSource;
372
- const commitBoundary = deps.commitBoundary ?? commitWriteTargetBoundary;
373
- const wasInstalled = (await sched.list()).some((entry) => entry.id === normalised);
374
- let sourceRestoreArmed = false;
375
- let installSucceeded = false;
376
- try {
377
- sourceRestoreArmed = true;
378
- await writeAsset(target.source, target.config, ref, updated);
379
- // Reinstall from the (just-updated) definition rather than only toggling
380
- // the comment. A plain toggle leaves a stale schedule in place if the
381
- // .yml's `schedule:` changed while the task was disabled — re-enabling
382
- // would silently keep the old cron line. install() renders the block with
383
- // both the current schedule and the new enabled state, and is idempotent.
384
- await sched.install(task);
385
- installSucceeded = true;
386
- commitBoundary(target, `Update tasks/${normalised}`);
387
- }
388
- catch (err) {
389
- const rollbackErrors = [];
390
- let sourceRestored = false;
391
- if (sourceRestoreArmed) {
392
- try {
393
- await restoreTaskSourceBytes(writeAsset, target.source, target.config, ref, filePath, yaml);
394
- sourceRestored = true;
395
- }
396
- catch (rollbackError) {
397
- rollbackErrors.push(rollbackError);
398
- }
399
- }
400
- if (installSucceeded) {
401
- try {
402
- if (wasInstalled)
403
- await sched.install(previousTask);
404
- else
405
- await sched.uninstall(normalised);
406
- }
407
- catch (rollbackError) {
408
- rollbackErrors.push(rollbackError);
409
- }
410
- }
411
- if (sourceRestored) {
412
- try {
413
- commitBoundary(target, `Restore tasks/${normalised}`);
414
- }
415
- catch (rollbackError) {
416
- rollbackErrors.push(rollbackError);
417
- }
418
- }
419
- if (rollbackErrors.length > 0) {
420
- const message = err instanceof Error ? err.message : String(err);
421
- throw new AggregateError([err, ...rollbackErrors], `${message}; rollback for task "${normalised}" was incomplete.`);
422
- }
423
- throw err;
424
- }
425
- return { id: normalised, enabled, backend: sched.name };
426
- }
427
198
  export async function akmTasksRun(id, options = {}) {
428
199
  const startedAt = new Date();
429
200
  let normalised;
@@ -441,7 +212,13 @@ export async function akmTasksRun(id, options = {}) {
441
212
  }
442
213
  let stashDir;
443
214
  try {
444
- stashDir = resolveStashDir();
215
+ // No --bundle uses the primary stash. With --bundle, resolve (read-only)
216
+ // the named bundle so the task file and
217
+ // its relative asset refs load from that bundle's path.
218
+ stashDir =
219
+ options.target !== undefined
220
+ ? resolveWriteTarget(loadConfig(), options.target, { requireWritable: false }).source.path
221
+ : resolveStashDir();
445
222
  }
446
223
  catch (failure) {
447
224
  recordTaskAttemptFailure({
@@ -452,9 +229,6 @@ export async function akmTasksRun(id, options = {}) {
452
229
  });
453
230
  throw failure;
454
231
  }
455
- const typeRoot = path.join(stashDir, "tasks");
456
- if (fs.existsSync(typeRoot))
457
- warnLegacyMdTaskFiles(typeRoot);
458
232
  const result = await runTask(normalised, { stashDir, scheduled: options.scheduled === true });
459
233
  const exitCode = result.status === "failed" && result.target.kind === "command" && result.detail?.exitCode === 78
460
234
  ? 78
@@ -468,26 +242,32 @@ export async function akmTasksRun(id, options = {}) {
468
242
  export async function akmTasksHistory(input) {
469
243
  const limit = input.limit !== undefined && input.limit > 0 ? input.limit : 50;
470
244
  const id = input.id ? normaliseTaskId(input.id) : undefined;
471
- const stashDir = resolveStashDir();
472
- const typeRoot = path.join(stashDir, "tasks");
473
- if (fs.existsSync(typeRoot))
474
- warnLegacyMdTaskFiles(typeRoot);
245
+ // History rows are keyed by task id in state.db, not per bundle.
475
246
  return { rows: readTaskHistory({ id, limit }) };
476
247
  }
477
248
  /**
478
- * Reconcile the on-disk task files with the OS scheduler.
249
+ * Reconcile the on-disk task files of ONE bundle with the OS scheduler.
479
250
  * • install missing tasks (after validating them — invalid files are
480
251
  * skipped with a per-task reason rather than aborting the whole sync)
481
252
  * • reinstall tasks whose schedule or enabled state changed in the .yml
482
253
  * (drift detected by comparing the backend's installed signature against
483
254
  * the signature the current definition would produce)
484
255
  * • remove orphan scheduler entries that no longer have a backing file
256
+ *
257
+ * `--bundle <bundle>` scopes the reconciliation to that bundle: the file set is
258
+ * the bundle's `tasks/*.yml` and — crucially — the scheduler entries considered
259
+ * are ONLY those attributed to the same bundle (parsed from the installed
260
+ * `--bundle` token; absent ⇒ primary). This is the security boundary that keeps
261
+ * "registering a bundle never activates code": a plain (primary) sync never
262
+ * installs from, updates, or removes another bundle's entries, and sync never
263
+ * scans all bundles. Activation happens only through explicit `add --bundle`
264
+ * (or `sync --bundle` on a bundle whose task files are already present).
485
265
  */
486
- export async function akmTasksSync(deps = {}) {
487
- const stashDir = resolveStashDir();
266
+ export async function akmTasksSync(deps = {}, bundleTarget, options = {}) {
267
+ const stashDir = resolveTaskInspectDir(bundleTarget);
268
+ // Primary-bundle scheduler entries omit --bundle; other bundles carry it.
269
+ const syncTarget = bundleTarget !== undefined && !isPrimaryStashPath(stashDir) ? bundleTarget : undefined;
488
270
  const typeRoot = path.join(stashDir, "tasks");
489
- if (fs.existsSync(typeRoot))
490
- warnLegacyMdTaskFiles(typeRoot);
491
271
  const fileIds = fs.existsSync(typeRoot)
492
272
  ? fs
493
273
  .readdirSync(typeRoot)
@@ -496,22 +276,30 @@ export async function akmTasksSync(deps = {}) {
496
276
  : [];
497
277
  const sched = deps.backend ?? selectBackend();
498
278
  const backend = sched.name;
499
- // Map id installed signature so sync can detect schedule/enabled drift on
500
- // tasks that already exist in the scheduler, not just presence/absence.
501
- const present = new Map((await sched.list()).map((t) => [t.id, t.signature]));
279
+ const installOpts = syncTarget !== undefined ? { target: syncTarget } : undefined;
280
+ const allEntries = options.rebind && sched.listForRebind ? await sched.listForRebind() : await sched.list();
281
+ // Attribution filter: only entries installed from THIS bundle are reconciled
282
+ // here. Entries carrying a `--bundle` for a different bundle are invisible to
283
+ // this sync — never removed, never touched.
284
+ const present = new Map(allEntries.filter((t) => sameBundle(t.target, syncTarget)).map((t) => [t.id, t]));
502
285
  const installed = [];
503
286
  const updated = [];
504
287
  const unchanged = [];
505
288
  const skipped = [];
289
+ const warnings = [];
506
290
  for (const id of fileIds) {
507
291
  const filePath = path.join(typeRoot, `${id}.yml`);
508
292
  let task;
509
293
  try {
510
294
  task = parseTaskDocument({ yaml: fs.readFileSync(filePath, "utf8"), filePath, id });
511
295
  await validateTaskDocument(task, { backend, stashDir });
512
- const obsoleteReason = obsoleteBackupTaskReason(task);
513
- if (obsoleteReason)
514
- throw new UsageError(obsoleteReason, "INVALID_FLAG_VALUE");
296
+ // A bare id can only be scheduled from ONE bundle at a time (scheduler ids
297
+ // are never namespaced). If this id is already scheduled from a different
298
+ // bundle, refuse rather than clobber it — surface it as a per-task skip so
299
+ // the rest of the sync still proceeds.
300
+ const foreign = allEntries.find((e) => e.id === id && !sameBundle(e.target, syncTarget));
301
+ if (foreign)
302
+ throw new UsageError(foreignScheduleMessage(id, foreign.target), "RESOURCE_ALREADY_EXISTS");
515
303
  }
516
304
  catch (err) {
517
305
  skipped.push({ id, reason: err instanceof Error ? err.message : String(err) });
@@ -531,8 +319,14 @@ export async function akmTasksSync(deps = {}) {
531
319
  continue;
532
320
  }
533
321
  if (!present.has(id)) {
534
- await sched.install(task);
535
- installed.push(id);
322
+ try {
323
+ const runtimeOpts = schedulerInstallOptions(installOpts, undefined, deps, options.rebind === true, `create scheduler entry for task "${id}"`, warnings);
324
+ await sched.install(task, runtimeOpts);
325
+ installed.push(id);
326
+ }
327
+ catch (error) {
328
+ skipped.push({ id, reason: error instanceof Error ? error.message : String(error) });
329
+ }
536
330
  continue;
537
331
  }
538
332
  // Already installed — reconcile against the current definition. Compare the
@@ -540,13 +334,15 @@ export async function akmTasksSync(deps = {}) {
540
334
  // When the backend can't produce a signature (no expectedSignature, or it
541
335
  // didn't record one), reinstall unconditionally — install() is idempotent,
542
336
  // so the cost is one crontab write and correctness is guaranteed.
543
- const installedSig = present.get(id);
544
- const expectedSig = sched.expectedSignature?.(task);
337
+ const installedEntry = present.get(id);
338
+ const runtimeOpts = schedulerInstallOptions(installOpts, options.rebind ? undefined : installedEntry, deps, options.rebind === true, `rebind scheduler entry for task "${id}"`, warnings);
339
+ const installedSig = installedEntry.signature;
340
+ const expectedSig = sched.expectedSignature?.(task, runtimeOpts);
545
341
  if (installedSig !== undefined && expectedSig !== undefined && installedSig === expectedSig) {
546
342
  unchanged.push(id);
547
343
  }
548
344
  else {
549
- await sched.install(task);
345
+ await sched.install(task, runtimeOpts);
550
346
  updated.push(id);
551
347
  }
552
348
  }
@@ -557,48 +353,69 @@ export async function akmTasksSync(deps = {}) {
557
353
  removed.push(installedId);
558
354
  }
559
355
  }
560
- return { installed, updated, removed, unchanged, skipped, backend: sched.name };
561
- }
562
- function obsoleteBackupTaskReason(task) {
563
- if (!task.enabled || task.target.kind !== "command")
564
- return undefined;
565
- const executableIndex = findBareAkmExecutableIndex(task.target.cmd);
566
- if (executableIndex === undefined)
567
- return undefined;
568
- const args = task.target.cmd.slice(executableIndex + 1);
569
- if (args.length !== 2 || args[0] !== "db" || args[1] !== "backups")
570
- return undefined;
571
- return (`Task "${task.id}" invokes obsolete \`akm db backups\`, which only listed legacy backups and is not a 0.9 backup command. ` +
572
- "AKM will not install or enable it; sync will keep any existing scheduler entry disabled, and the task file is unchanged. " +
573
- "Use `akm backup create --for 0.9.0` for an explicit migration recovery snapshot.");
356
+ return {
357
+ installed,
358
+ updated,
359
+ removed,
360
+ unchanged,
361
+ skipped,
362
+ backend: sched.name,
363
+ ...(warnings.length > 0 ? { warnings } : {}),
364
+ };
574
365
  }
575
- export async function akmTasksDoctor() {
366
+ export async function akmTasksDoctor(deps = {}) {
576
367
  const warnings = [];
577
- let invocation = { argv: [], via: "unresolved" };
368
+ let invocation = {
369
+ argv: [],
370
+ via: "unresolved",
371
+ };
578
372
  try {
579
- const r = resolveAkmInvocation();
580
- invocation = { argv: r.argv, via: r.via };
373
+ const r = (deps.resolveInvocation ?? resolveAkmInvocation)();
374
+ invocation = { argv: r.argv, via: r.via, kind: r.kind, eligible: r.eligible };
581
375
  }
582
376
  catch (err) {
583
377
  warnings.push(err instanceof Error ? err.message : String(err));
584
378
  }
585
- try {
586
- const stashDir = resolveStashDir();
587
- const typeRoot = path.join(stashDir, "tasks");
588
- if (fs.existsSync(typeRoot))
589
- warnLegacyMdTaskFiles(typeRoot);
379
+ const skipNativeInspection = process.env.BUN_TEST === "1" && !deps.backend;
380
+ const sched = deps.backend ?? (skipNativeInspection ? undefined : selectBackend());
381
+ const backend = sched?.name ?? backendNameForPlatform();
382
+ let installed = [];
383
+ if (skipNativeInspection) {
384
+ warnings.push("Native scheduler inspection is skipped inside the bun test harness.");
590
385
  }
591
- catch {
592
- // doctor must never fail on stash-resolution; the warning is best-effort
386
+ else {
387
+ try {
388
+ installed = await sched.list();
389
+ }
390
+ catch (error) {
391
+ warnings.push(`Unable to inspect installed ${backend} definitions: ${error instanceof Error ? error.message : String(error)}`);
392
+ }
593
393
  }
594
- const backend = backendNameForPlatform();
595
- const config = loadConfig();
394
+ const bindings = groupInstalledBindings(installed, invocation);
395
+ // Report the EFFECTIVE engine view — the same one the runner resolves —
396
+ // so doctor never says "no engine" on an install where tasks actually run.
397
+ const { config } = withEngineFallback(loadConfig());
596
398
  const defaultEngine = config.defaults?.engine;
597
399
  const engines = Object.keys(config.engines ?? {});
598
400
  // §6.1: surface the effective triage settings for the default improve
599
401
  // strategy. The struct is a fixed shape, so this is a deliberate addition.
600
402
  const improveStrategyName = typeof config.defaults?.improveStrategy === "string" ? config.defaults.improveStrategy : "default";
601
- const triage = resolveImproveStrategy(config.defaults?.improveStrategy, config).config.processes?.triage;
403
+ // D8 report the EFFECTIVE strategy, not the raw one. Resolving the raw
404
+ // strategy here would report `applyMode: "promote"` for a promote strategy
405
+ // under a review-first config, while the run actually uses "queue" — a doctor
406
+ // command lying about the thing it exists to diagnose.
407
+ const rawStrategy = resolveImproveStrategy(config.defaults?.improveStrategy, config).config;
408
+ const { config: effectiveStrategy, gated } = applyAutonomyGate(rawStrategy, config);
409
+ const autonomyEnabled = isImproveAutonomyEnabled(config);
410
+ // Memory cleanup has no strategy flag to downgrade, so add that direct lane
411
+ // to the strategy-derived gate report.
412
+ const allGated = autonomyEnabled ? [] : [...gated, ...describeGatedLanes(configuredDirectAutonomyLanes())];
413
+ const improveAutonomy = {
414
+ enabled: autonomyEnabled,
415
+ configKey: IMPROVE_AUTONOMY_CONFIG_KEY,
416
+ gatedLanes: allGated.map((entry) => ({ lane: entry.lane, reason: entry.reason })),
417
+ };
418
+ const triage = effectiveStrategy.processes?.triage;
602
419
  const improveTriage = triage
603
420
  ? {
604
421
  defaultStrategy: improveStrategyName,
@@ -610,17 +427,111 @@ export async function akmTasksDoctor() {
610
427
  return {
611
428
  backend,
612
429
  akm: invocation,
430
+ caller: invocation,
431
+ bindings,
432
+ ...(bindings.some((binding) => !binding.status.includes("ok"))
433
+ ? { remediation: "akm task sync --rebind" }
434
+ : {}),
613
435
  logDir: getTaskLogDir(),
614
436
  historyDir: getTaskHistoryDir(),
615
437
  engine: { defaultEngine, available: engines },
616
- stale: collectStaleTaskIds(),
617
- staleGeneratedCommands: collectStaleGeneratedCommands(),
618
438
  scheduleSubset: SCHEDULE_SUPPORTED_SUBSET_HINT,
619
439
  warnings,
440
+ improveAutonomy,
620
441
  ...(improveTriage ? { improveTriage } : {}),
621
442
  };
622
443
  }
623
444
  // ── helpers ─────────────────────────────────────────────────────────────────
445
+ function schedulerInstallOptions(base, installed, deps, explicitRebind, operation, warnings = []) {
446
+ if (installed && !explicitRebind) {
447
+ return {
448
+ ...base,
449
+ binding: installed.binding,
450
+ contextPath: installed.contextPath,
451
+ };
452
+ }
453
+ // Injected backends can own their default runtime unless a resolver is supplied.
454
+ if (deps.backend && !deps.schedulerRuntime)
455
+ return base;
456
+ const runtime = deps.schedulerRuntime?.() ?? prepareSchedulerRuntime(explicitRebind, operation);
457
+ // --rebind bypasses the eligibility refusal in prepareSchedulerRuntime; warn once
458
+ // per sync run rather than silently writing a mutable/unproven binary into cron.
459
+ if (explicitRebind && runtime.eligible === false && warnings.length === 0) {
460
+ warnings.push(`--rebind bound scheduled tasks to an ineligible ${runtime.kind ?? "unknown"} invocation (${runtime.binding.join(" ")}); scheduled runs will invoke a mutable, unproven binary. Install akm via \`npm install --global akm-cli\` or a standalone release, then re-run \`akm task sync --rebind\`.`);
461
+ }
462
+ return { ...base, binding: runtime.binding, contextPath: runtime.contextPath };
463
+ }
464
+ export function prepareSchedulerRuntime(explicitRebind, operation, deps = {}) {
465
+ const invocation = (deps.resolveInvocation ?? resolveAkmInvocation)();
466
+ if (!invocation.eligible && !explicitRebind) {
467
+ throw new UsageError(`Refusing to ${operation} from an ineligible ${invocation.kind ?? "unknown"} invocation (${invocation.argv.join(" ")}).`, "INVALID_FLAG_VALUE", "npm-global ownership could not be verified. Run `npm install --global akm-cli` and use that launcher, use a standalone installation, or explicitly repeat the operation with --rebind.");
468
+ }
469
+ const contextPath = (deps.writeDescriptor ?? writeSchedulerContextDescriptor)(schedulerContextDescriptor());
470
+ return { binding: invocation.argv, contextPath, eligible: invocation.eligible, kind: invocation.kind };
471
+ }
472
+ function groupInstalledBindings(entries, invocation) {
473
+ const groups = new Map();
474
+ for (const entry of entries) {
475
+ const argv = entry.binding;
476
+ const status = inspectInstalledBinding(entry, invocation);
477
+ const key = JSON.stringify([argv, entry.contextPath, status]);
478
+ const existing = groups.get(key);
479
+ if (existing) {
480
+ existing.taskIds.push(entry.id);
481
+ continue;
482
+ }
483
+ groups.set(key, {
484
+ argv,
485
+ contextPath: entry.contextPath,
486
+ taskIds: [entry.id],
487
+ status,
488
+ });
489
+ }
490
+ return [...groups.values()].map((group) => ({ ...group, taskIds: group.taskIds.sort() }));
491
+ }
492
+ function inspectInstalledBinding(entry, invocation) {
493
+ const status = [];
494
+ const binding = entry.binding;
495
+ if (!(invocation.eligible === true && sameArgv(binding, invocation.argv)) &&
496
+ binding.some((part) => /(?:^|[\\/])src[\\/]cli\.ts$|(?:^|[\\/])dist[\\/](?:cli\.js|cli-node\.mjs)$/i.test(part) ||
497
+ (path.isAbsolute(part) && hasGitAncestor(part)))) {
498
+ status.push("checkout");
499
+ }
500
+ if (binding.some((part) => part === "akm" || part === "bun" || part === "node"))
501
+ status.push("path-selected");
502
+ try {
503
+ validateSchedulerContextDescriptor(entry.contextPath);
504
+ }
505
+ catch {
506
+ status.push("invalid-context");
507
+ }
508
+ const absolutePaths = [...binding.filter((part) => path.isAbsolute(part)), entry.contextPath];
509
+ if (absolutePaths.some((part) => !fs.existsSync(part)))
510
+ status.push("missing-path");
511
+ if (status.length === 0)
512
+ status.push("ok");
513
+ return status;
514
+ }
515
+ function sameArgv(left, right) {
516
+ return left.length === right.length && left.every((value, index) => value === right[index]);
517
+ }
518
+ function hasGitAncestor(file) {
519
+ let current;
520
+ try {
521
+ current = path.dirname(fs.realpathSync(file));
522
+ }
523
+ catch {
524
+ return false;
525
+ }
526
+ for (;;) {
527
+ if (fs.existsSync(path.join(current, ".git")))
528
+ return true;
529
+ const parent = path.dirname(current);
530
+ if (parent === current)
531
+ return false;
532
+ current = parent;
533
+ }
534
+ }
624
535
  function taskAssetRef(id) {
625
536
  return { type: "task", name: id };
626
537
  }
@@ -629,8 +540,55 @@ async function restoreTaskSourceBytes(writeAsset, source, config, ref, filePath,
629
540
  // The normal write path adds a trailing newline; rollback restores the raw snapshot exactly.
630
541
  fs.writeFileSync(filePath, yaml, "utf8");
631
542
  }
632
- function resolveTaskWriteTarget() {
633
- return resolveWriteTarget(loadConfig());
543
+ /**
544
+ * Resolve the bundle a mutating/run task command targets. Returns the resolved
545
+ * write/read target, its stash path, and the `--bundle <bundle>` token to embed
546
+ * in scheduled invocations. The primary bundle uses the target-less form.
547
+ */
548
+ function resolveTaskBundle(target, opts) {
549
+ const selected = resolveWriteTarget(loadConfig(), target, { requireWritable: opts.requireWritable });
550
+ const resolved = opts.requireWritable ? prepareWriteTargetForMutation(selected) : selected;
551
+ const stashDir = resolved.source.path;
552
+ const installTarget = isPrimaryStashPath(stashDir) ? undefined : (resolved.selector ?? resolved.source.name);
553
+ return { resolved, stashDir, installTarget };
554
+ }
555
+ /**
556
+ * Resolve the tasks/ directory a read/inspect command operates on. No
557
+ * `--bundle` uses the primary stash; `--bundle X` resolves bundle X read-only.
558
+ */
559
+ function resolveTaskInspectDir(target) {
560
+ if (target === undefined)
561
+ return resolveStashDir();
562
+ return resolveWriteTarget(loadConfig(), target, { requireWritable: false }).source.path;
563
+ }
564
+ /** True when `candidate` resolves to the same directory as the primary stash. */
565
+ function isPrimaryStashPath(candidate) {
566
+ let primary;
567
+ try {
568
+ primary = path.resolve(resolveStashDir());
569
+ }
570
+ catch {
571
+ return false;
572
+ }
573
+ return path.resolve(candidate) === primary;
574
+ }
575
+ /** Two bundle attributions match when both are the primary (undefined) or equal names. */
576
+ function sameBundle(a, b) {
577
+ return (a ?? undefined) === (b ?? undefined);
578
+ }
579
+ function foreignScheduleMessage(id, existingTarget) {
580
+ const where = existingTarget === undefined ? "the default bundle" : `bundle "${existingTarget}"`;
581
+ return `Task id "${id}" is already scheduled from ${where}; rename the task or disable the existing one first.`;
582
+ }
583
+ /**
584
+ * Refuse to schedule an id already installed from a DIFFERENT bundle. Scheduler
585
+ * ids are the bare task id (never namespaced), so a single id can be active from
586
+ * only one bundle at a time — a collision is a hard error, not an auto-rename.
587
+ */
588
+ function assertNoForeignSchedule(entries, id, installTarget) {
589
+ const foreign = entries.find((entry) => entry.id === id && !sameBundle(entry.target, installTarget));
590
+ if (foreign)
591
+ throw new UsageError(foreignScheduleMessage(id, foreign.target), "RESOURCE_ALREADY_EXISTS");
634
592
  }
635
593
  function renderTaskYaml(input) {
636
594
  const obj = { version: 2, schedule: input.schedule, enabled: input.enabled };
@@ -667,101 +625,6 @@ function renderTaskYaml(input) {
667
625
  obj.tags = input.tags;
668
626
  return yamlStringify(obj);
669
627
  }
670
- function isStaleTaskError(err) {
671
- return err instanceof UsageError && err.code === "TASK_SCHEMA_VERSION_UNSUPPORTED";
672
- }
673
- function warnStaleTaskFiles(ids) {
674
- process.stderr.write(`WARNING: ${ids.length} task file(s) use an unsupported task schema version and were not loaded.\n` +
675
- ` Use version: 2. See docs/migration/v0.8-to-v0.9.md#engine-and-task-assets.\n` +
676
- ` Affected: ${ids.map((id) => `tasks/${id}.yml`).join(", ")}\n`);
677
- }
678
- function collectStaleTaskIds() {
679
- const typeRoot = path.join(resolveStashDir(), "tasks");
680
- if (!fs.existsSync(typeRoot))
681
- return [];
682
- const stale = [];
683
- for (const file of fs.readdirSync(typeRoot)) {
684
- if (!file.endsWith(".yml"))
685
- continue;
686
- const id = file.slice(0, -4);
687
- try {
688
- parseTaskDocument({
689
- yaml: fs.readFileSync(path.join(typeRoot, file), "utf8"),
690
- filePath: path.join(typeRoot, file),
691
- id,
692
- });
693
- }
694
- catch (err) {
695
- if (isStaleTaskError(err))
696
- stale.push(id);
697
- }
698
- }
699
- return stale;
700
- }
701
- // Old-spelling match keys for the default-task commands whose retired
702
- // `--auto-accept safe` flag is dropped in the `replacement`. Each id lists BOTH
703
- // deprecated spellings that can survive in a v2 task file: the original
704
- // `--profile X --auto-accept safe` and the intermediate `--strategy X
705
- // --auto-accept safe` (what the 0.8→0.9 migration writes — parser normalization
706
- // only rewrites `--profile`→`--strategy` for legacy v1 files, so a stored v2
707
- // file keeps whichever spelling it was minted with). Without the `--strategy`
708
- // variant, migrated default tasks match no key and warn on every run until 0.10
709
- // (chunk-6 ledger residue).
710
- const STALE_GENERATED_COMMANDS = {
711
- "akm-improve-frequent": {
712
- commands: [
713
- "akm improve --profile frequent --auto-accept safe",
714
- "akm improve --strategy frequent --auto-accept safe",
715
- ],
716
- replacement: "akm improve --strategy frequent",
717
- },
718
- "akm-improve-consolidate": {
719
- commands: [
720
- "akm improve --profile consolidate --auto-accept safe",
721
- "akm improve --strategy consolidate --auto-accept safe",
722
- ],
723
- replacement: "akm improve --strategy consolidate",
724
- },
725
- "akm-improve-nightly": {
726
- commands: [
727
- "akm improve --profile thorough --auto-accept safe",
728
- "akm improve --strategy thorough --auto-accept safe",
729
- ],
730
- replacement: "akm improve --strategy thorough",
731
- },
732
- "akm-improve-catchup": {
733
- commands: ["akm improve --profile catchup --auto-accept safe", "akm improve --strategy catchup --auto-accept safe"],
734
- replacement: "akm improve --strategy catchup",
735
- },
736
- "akm-graph-refresh-weekly": {
737
- commands: [
738
- "akm improve --profile graph-refresh --auto-accept safe",
739
- "akm improve --strategy graph-refresh --auto-accept safe",
740
- ],
741
- replacement: "akm improve --strategy graph-refresh",
742
- },
743
- };
744
- function collectStaleGeneratedCommands() {
745
- const typeRoot = path.join(resolveStashDir(), "tasks");
746
- if (!fs.existsSync(typeRoot))
747
- return [];
748
- const stale = [];
749
- for (const [id, expected] of Object.entries(STALE_GENERATED_COMMANDS)) {
750
- const filePath = path.join(typeRoot, `${id}.yml`);
751
- if (!fs.existsSync(filePath))
752
- continue;
753
- try {
754
- const task = parseTaskDocument({ yaml: fs.readFileSync(filePath, "utf8"), filePath, id });
755
- if (task.target.kind === "command" && expected.commands.includes(task.target.cmd.join(" "))) {
756
- stale.push({ id, replacement: expected.replacement });
757
- }
758
- }
759
- catch {
760
- // Stale-schema reporting owns files that cannot be parsed.
761
- }
762
- }
763
- return stale;
764
- }
765
628
  function parseJsonObjectArg(raw) {
766
629
  let parsed;
767
630
  try {
@@ -799,11 +662,9 @@ export function setEnabledInYaml(yaml, enabled) {
799
662
  // Re-exported so tests can verify the validator path directly.
800
663
  // Re-export error classes consumed by callers that want to instanceof-check.
801
664
  // Re-export this so the CLI can decide what process exit code to use after
802
- // `akm tasks run` completes.
665
+ // `akm task run` completes.
803
666
  export { ConfigError, exitCodeForStatus, NotFoundError, parseTaskDocument, UsageError };
804
- // Accept a bare task id or the canonical 0.9.0 `[bundle//]tasks/<id>` ref
805
- // (ref-grammar decision D-R3). The pre-0.9.0 `task:<id>` colon grammar is
806
- // retired and rejected loudly — it appears NOWHERE after the flip.
667
+ // Accept a bare task id or the canonical `[bundle//]tasks/<id>` ref.
807
668
  export function parseTaskRef(input) {
808
669
  const trimmed = input.trim();
809
670
  // Canonical conceptId form: `[bundle//]tasks/<id>`. A `/` unambiguously marks
@@ -821,11 +682,5 @@ export function parseTaskRef(input) {
821
682
  }
822
683
  throw new UsageError(`Expected a task id or tasks/<id> ref, got "${input}".`, "INVALID_FLAG_VALUE");
823
684
  }
824
- // Legacy `task:<id>` grammar is gone in 0.9.0 (D-R3) — reject it with a typed
825
- // error that names the new form so muscle-memory callers get a clear fix.
826
- if (trimmed.includes(":")) {
827
- const legacyName = trimmed.slice(trimmed.indexOf(":") + 1);
828
- throw new UsageError(`The \`task:<id>\` ref grammar was removed in 0.9.0 — use the bare id or \`tasks/${legacyName || "<id>"}\`.`, "INVALID_FLAG_VALUE");
829
- }
830
685
  return { id: normaliseTaskId(trimmed) };
831
686
  }