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
@@ -4,84 +4,30 @@
4
4
  import { UsageError } from "../../core/errors.js";
5
5
  import { decodeCanonicalPlan } from "../ir/plan-hash.js";
6
6
  import { WORKFLOW_IR_VERSION } from "../ir/schema.js";
7
- /** One policy authority for executable versus inspection-only historical runs. */
7
+ /** Validate that a live run carries exactly the current frozen-plan format. */
8
8
  export function classifyWorkflowRunPlan(row) {
9
9
  const runId = row.id ?? "(unknown)";
10
10
  if (!row.plan_json) {
11
- if (row.plan_ir_version === WORKFLOW_IR_VERSION) {
12
- return {
13
- support: "corrupt-plan",
14
- irVersion: row.plan_ir_version,
15
- error: `Workflow run ${runId} declares workflow IR version ${row.plan_ir_version} but has no frozen plan.`,
16
- };
17
- }
18
- return {
19
- support: row.plan_ir_version === null || row.plan_ir_version === undefined ? "missing-plan" : "unsupported-version",
20
- irVersion: row.plan_ir_version ?? null,
21
- error: row.plan_ir_version === null || row.plan_ir_version === undefined
22
- ? `Workflow run ${runId} has no executable workflow IR plan.`
23
- : `Workflow run ${runId} uses unsupported workflow IR version ${String(row.plan_ir_version)} and has no frozen plan.`,
24
- };
25
- }
26
- let raw;
27
- try {
28
- raw = JSON.parse(row.plan_json);
29
- }
30
- catch {
31
- if (row.plan_ir_version !== WORKFLOW_IR_VERSION) {
32
- return {
33
- support: row.plan_ir_version === null || row.plan_ir_version === undefined ? "missing-plan" : "unsupported-version",
34
- irVersion: row.plan_ir_version ?? null,
35
- error: `Workflow run ${runId} has malformed historical frozen plan JSON that cannot be executed.`,
36
- };
37
- }
38
- return {
39
- support: "corrupt-plan",
40
- irVersion: row.plan_ir_version ?? null,
41
- error: `Workflow run ${runId} has corrupt frozen plan JSON.`,
42
- };
43
- }
44
- const decodedVersion = typeof raw === "object" && raw !== null ? raw.irVersion : null;
45
- if (!Number.isSafeInteger(decodedVersion) || decodedVersion < 1) {
46
- if (row.plan_ir_version !== WORKFLOW_IR_VERSION) {
47
- return {
48
- support: row.plan_ir_version === null || row.plan_ir_version === undefined ? "missing-plan" : "unsupported-version",
49
- irVersion: row.plan_ir_version ?? null,
50
- error: `Workflow run ${runId} has historical frozen plan data with no supported IR version.`,
51
- };
52
- }
53
11
  return {
54
- support: "corrupt-plan",
12
+ support: "missing-plan",
55
13
  irVersion: row.plan_ir_version ?? null,
56
- error: `Workflow run ${runId} has a missing or invalid frozen plan IR version.`,
14
+ error: `Workflow run ${runId} has no frozen workflow plan.`,
57
15
  };
58
16
  }
59
- if (row.plan_ir_version !== null && row.plan_ir_version !== undefined && row.plan_ir_version !== decodedVersion) {
60
- if (row.plan_ir_version !== WORKFLOW_IR_VERSION && decodedVersion !== WORKFLOW_IR_VERSION) {
61
- return {
62
- support: "unsupported-version",
63
- irVersion: decodedVersion,
64
- error: `Workflow run ${runId} uses unsupported workflow IR version ${String(decodedVersion)} with mismatched historical metadata.`,
65
- };
66
- }
67
- return {
68
- support: "corrupt-plan",
69
- irVersion: decodedVersion,
70
- error: `Workflow run ${runId} has mismatched stored plan IR version (${String(row.plan_ir_version)} != ${String(decodedVersion)}).`,
71
- };
72
- }
73
- if (decodedVersion !== WORKFLOW_IR_VERSION) {
17
+ if (row.plan_ir_version !== null &&
18
+ row.plan_ir_version !== undefined &&
19
+ row.plan_ir_version !== WORKFLOW_IR_VERSION) {
74
20
  return {
75
21
  support: "unsupported-version",
76
- irVersion: decodedVersion,
77
- error: `Workflow run ${runId} uses unsupported workflow IR version ${String(decodedVersion)}.`,
22
+ irVersion: row.plan_ir_version,
23
+ error: `Workflow run ${runId} uses unsupported workflow IR version ${row.plan_ir_version}; this runtime requires version ${WORKFLOW_IR_VERSION}.`,
78
24
  };
79
25
  }
80
26
  if (row.plan_ir_version !== WORKFLOW_IR_VERSION) {
81
27
  return {
82
28
  support: "corrupt-plan",
83
- irVersion: row.plan_ir_version ?? null,
84
- error: `Workflow run ${runId} has no stored plan IR version.`,
29
+ irVersion: null,
30
+ error: `Workflow run ${runId} does not declare workflow IR version ${WORKFLOW_IR_VERSION}.`,
85
31
  };
86
32
  }
87
33
  try {
@@ -92,25 +38,20 @@ export function classifyWorkflowRunPlan(row) {
92
38
  };
93
39
  }
94
40
  catch (cause) {
95
- return { support: "corrupt-plan", irVersion: 3, error: cause instanceof Error ? cause.message : String(cause) };
41
+ return {
42
+ support: "corrupt-plan",
43
+ irVersion: WORKFLOW_IR_VERSION,
44
+ error: cause instanceof Error ? cause.message : String(cause),
45
+ };
96
46
  }
97
47
  }
98
- /** Reject an execution mutation while preserving inspection and abandon access. */
48
+ /** Reject any operation that requires a valid current frozen plan. */
99
49
  export function requireExecutableWorkflowPlan(row) {
100
50
  const classified = classifyWorkflowRunPlan(row);
101
51
  if (classified.support === "supported")
102
52
  return classified.plan;
103
- if (classified.support === "missing-plan" || classified.support === "unsupported-version") {
104
- throw new UsageError(`${classified.error} This historical run is inspection-only; abandon it with \`akm workflow abandon ${row.id ?? "<run>"}\` and start a new run.`, "WORKFLOW_IR_VERSION_UNSUPPORTED");
105
- }
106
53
  throw new UsageError(classified.error, "INVALID_JSON_ARGUMENT");
107
54
  }
108
- /** Abandon is the sole mutation allowed for a historical run; corrupt v3 data is never mutated. */
109
- export function requireAbandonableWorkflowPlan(row) {
110
- const classified = classifyWorkflowRunPlan(row);
111
- if (classified.support === "corrupt-plan")
112
- throw new UsageError(classified.error, "INVALID_JSON_ARGUMENT");
113
- }
114
55
  /** Project persisted spine rows from the decoded plan, never from the mutable source asset. */
115
56
  export function frozenStepRows(plan) {
116
57
  return plan.steps.map((step) => ({
@@ -2,26 +2,27 @@
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
  import { randomUUID } from "node:crypto";
5
+ import { parseBundleRef } from "../../core/asset/asset-ref.js";
5
6
  import { loadConfig } from "../../core/config/config.js";
6
- import { NotFoundError, UsageError } from "../../core/errors.js";
7
+ import { ConfigError, NotFoundError, UsageError } from "../../core/errors.js";
7
8
  import { appendEvent } from "../../core/events.js";
8
- import { canonicalizeWorkflowName } from "../../core/recognition-util.js";
9
9
  import { warn } from "../../core/warn.js";
10
+ import { insertEventOnce } from "../../storage/repositories/events-repository.js";
10
11
  import { withWorkflowRunsRepo, } from "../../storage/repositories/workflow-runs-repository.js";
11
12
  import { getCurrentWorkflowScopeKey } from "../authoring/scope-key.js";
12
13
  import { frozenSummaryJudge } from "../exec/frozen-judge.js";
13
14
  import { detectSecretShapedParams } from "../exec/param-secrets.js";
14
- import { collectProgramWarnings } from "../ir/compile.js";
15
+ import { collectWorkflowWarnings } from "../ir/compile.js";
15
16
  import { compileResolveFreezeWorkflow } from "../ir/freeze.js";
16
- import { validateWorkflowParams } from "../ir/params.js";
17
+ import { materializeWorkflowParameterFlags, validateWorkflowParams } from "../ir/params.js";
17
18
  import { canonicalPlanJson, computePlanHash } from "../ir/plan-hash.js";
18
19
  import { decodeWorkflowPlanV3, WORKFLOW_IR_VERSION } from "../ir/schema.js";
19
20
  import { validateStepSummary } from "../validate-summary.js";
20
21
  import { resolveAgentIdentity } from "./agent-identity.js";
21
22
  import { evaluateCheckin } from "./checkin.js";
22
- import { assertWorkflowSpineMatchesPlan, classifyWorkflowRunPlan, frozenStepRows, requireAbandonableWorkflowPlan, requireExecutableWorkflowPlan, } from "./plan-classifier.js";
23
+ import { assertWorkflowSpineMatchesPlan, classifyWorkflowRunPlan, frozenStepRows, requireExecutableWorkflowPlan, } from "./plan-classifier.js";
23
24
  import { evaluateStaleUnits } from "./unit-checkin.js";
24
- import { canonicalWorkflowRunRef, loadWorkflowAsset, parseWorkflowRefInput, resolveWorkflowEntryId, } from "./workflow-asset-loader.js";
25
+ import { canonicalizeWorkflowRefInput, loadWorkflowAsset, resolveWorkflowEntryId } from "./workflow-asset-loader.js";
25
26
  /** Clip bound for a unit's `result_json` on the `--units` diagnostic surface. */
26
27
  const UNIT_DIAGNOSTIC_CLIP = 2000;
27
28
  function toUnitDiagnostic(row, stale, plannedEngine) {
@@ -61,7 +62,6 @@ function toUnitDiagnostic(row, stale, plannedEngine) {
61
62
  engine: row.engine ?? null,
62
63
  runtimeKind: row.engine && (row.runner === "llm" || row.runner === "agent" || row.runner === "sdk") ? row.runner : null,
63
64
  platform: plannedEngine?.kind === "agent" ? plannedEngine.platform : null,
64
- ...(!row.engine && row.runner ? { legacyRunnerSelector: row.runner } : {}),
65
65
  };
66
66
  }
67
67
  export async function startWorkflowRun(ref, params = {}, options) {
@@ -70,34 +70,39 @@ export async function startWorkflowRun(ref, params = {}, options) {
70
70
  // persist it on the run row in the same transaction as the insert. Every
71
71
  // later invocation executes this snapshot — the asset file is never re-read
72
72
  // for an in-flight run; re-planning is an explicit new run.
73
- const plan = decodeWorkflowPlanV3(compileResolveFreezeWorkflow(asset, loadConfig()).plan);
74
- // Non-fatal WARNINGS (redesign addendum): a YAML program's untyped-step and
75
- // undeclared-param advisories surface as `warn()` lines at start (stderr,
76
- // consistent with the repo's other author-facing warnings) without blocking
77
- // the run. Markdown workflows carry no `program` and warn about nothing.
78
- if (asset.program) {
79
- for (const w of collectProgramWarnings(asset.program)) {
80
- warn(`workflow start: ${asset.path}:${w.line} — ${w.message}`);
81
- }
73
+ const frozen = compileResolveFreezeWorkflow(asset, loadConfig());
74
+ const plan = decodeWorkflowPlanV3(frozen.plan);
75
+ if (options?.parameterFlags?.length && Object.keys(params).length > 0) {
76
+ throw new UsageError("Workflow parameters must use either an object or per-parameter flags, not both.");
77
+ }
78
+ const effectiveParams = options?.parameterFlags?.length
79
+ ? materializeWorkflowParameterFlags(plan, options.parameterFlags)
80
+ : params;
81
+ // Non-fatal WARNINGS: untyped-step and undeclared-param advisories surface
82
+ // as `warn()` lines at start (stderr, consistent with the repo's other
83
+ // author-facing warnings) without blocking the run.
84
+ for (const w of collectWorkflowWarnings(asset.document)) {
85
+ warn(`workflow run: ${asset.path}:${w.line} — ${w.message}`);
82
86
  }
83
- // Reviewer #12: validate supplied `--params` against the frozen param
87
+ // Reviewer #12: validate supplied parameters against the frozen param
84
88
  // schemas BEFORE creating the run, so a type-mismatched param (e.g. a string
85
89
  // for a `{ type: array }` param) is rejected with actionable errors instead
86
90
  // of flowing silently into a unit prompt. Programs without declared param
87
91
  // schemas (and every Markdown workflow) validate trivially.
88
- const paramErrors = validateWorkflowParams(plan, params);
92
+ const paramErrors = validateWorkflowParams(plan, effectiveParams);
89
93
  if (paramErrors.length > 0) {
90
- throw new UsageError(`Cannot start ${asset.ref}: the supplied --params do not satisfy the workflow's declared parameter schemas:\n` +
94
+ throw new UsageError(`Cannot start ${asset.ref}: the supplied parameters do not satisfy the workflow's declared schemas:\n` +
91
95
  paramErrors.map((e) => ` - ${e}`).join("\n"), "INVALID_JSON_ARGUMENT");
92
96
  }
93
97
  const planJson = canonicalPlanJson(plan);
94
98
  const planHash = computePlanHash(plan);
99
+ const workflowRefs = await workflowRunRefSet(asset.ref, ref);
95
100
  return withWorkflowRunsRepo(async (repo) => {
96
101
  const now = new Date().toISOString();
97
102
  const runId = randomUUID();
98
103
  const scopeKey = getCurrentWorkflowScopeKey();
99
104
  const currentStepId = plan.steps[0]?.stepId ?? null;
100
- const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref);
105
+ const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref, asset.adapterId);
101
106
  // Capture the agent harness + session driving this run. Explicit options
102
107
  // win; otherwise fall back to best-effort environment detection. This is
103
108
  // identity-only — no background thread or timer is started here.
@@ -107,27 +112,28 @@ export async function startWorkflowRun(ref, params = {}, options) {
107
112
  // Concurrency guard (#485): if an active run already exists in this
108
113
  // (workflow_ref, scope_key) pair, refuse to create a parallel run unless
109
114
  // `force: true` is set. Previously every call inserted unconditionally,
110
- // so two terminals running `akm workflow start <ref>` left two runs
111
- // racing; `akm workflow next` then non-deterministically picked one.
112
- if (!options?.force) {
113
- const existing = repo.findActiveRunForScope(asset.ref, scopeKey);
114
- if (existing) {
115
- throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
116
- `Use 'akm workflow next ${asset.ref}' to resume it, 'akm workflow abandon ${existing.id}' to give up on it, or pass --force to start a parallel run.`, "RESOURCE_ALREADY_EXISTS");
117
- }
118
- }
115
+ // so two terminals starting the same workflow could leave two runs racing.
116
+ // The
117
+ // active-alias query and all inserts now share this immediate transaction.
119
118
  // #506: arm a file-signal check-in (a timestamp, NOT a background thread —
120
119
  // per the workflow-agent check-in ADR) so a stalled run can be
121
120
  // re-targeted with a `continue` directive. The agent harness + session id
122
121
  // are already resolved above (agentHarness/agentSessionId, from #501).
123
- repo.transaction(() => {
122
+ repo.immediateTransaction(() => {
123
+ if (!options?.force) {
124
+ const existing = repo.findActiveRunForScope(workflowRefs, scopeKey);
125
+ if (existing) {
126
+ throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
127
+ `Use 'akm workflow run ${asset.ref}' to resume it or 'akm workflow abandon ${existing.id}' to give up on it.`, "RESOURCE_ALREADY_EXISTS");
128
+ }
129
+ }
124
130
  repo.insertRun({
125
131
  id: runId,
126
132
  workflowRef: asset.ref,
127
133
  scopeKey,
128
134
  workflowEntryId,
129
135
  workflowTitle: asset.title,
130
- paramsJson: JSON.stringify(params),
136
+ paramsJson: JSON.stringify(effectiveParams),
131
137
  currentStepId,
132
138
  createdAt: now,
133
139
  updatedAt: now,
@@ -143,19 +149,23 @@ export async function startWorkflowRun(ref, params = {}, options) {
143
149
  completionJson: step.completionJson,
144
150
  sequenceIndex: step.sequenceIndex,
145
151
  })));
146
- // Same transaction as the insert: a run row never exists without its
147
- // frozen plan (rows with NULL plan_json are pre-006 legacy runs).
152
+ // Same transaction as the insert: a run row never exists without its frozen plan.
148
153
  repo.setRunPlan(runId, planJson, planHash, WORKFLOW_IR_VERSION);
149
154
  });
150
155
  const result = await getWorkflowStatus(runId);
151
156
  // #13: params are declared non-secret (they are copied verbatim into every
152
157
  // unit prompt and hashed into the unit identity, so they cannot be redacted
153
- // without breaking the driver protocol). Surface a loud, best-effort warning
158
+ // without breaking replay determinism). Surface a loud, best-effort warning
154
159
  // when a param LOOKS like a credential so the author moves it to an env
155
160
  // binding. Advisory only — never blocks the start.
156
- const secretWarnings = detectSecretShapedParams(params);
161
+ const secretWarnings = detectSecretShapedParams(effectiveParams);
157
162
  if (secretWarnings.length > 0)
158
163
  result.warnings = [...(result.warnings ?? []), ...secretWarnings];
164
+ // The implicit engine fallback is announced ONCE, here at run creation —
165
+ // the frozen plan records the engine actually used, so a resume never
166
+ // re-announces a decision it did not make.
167
+ if (frozen.engineAnnouncement)
168
+ result.warnings = [...(result.warnings ?? []), frozen.engineAnnouncement];
159
169
  // 07 P1-B: emit only the run id + status — NOT the raw workflowTitle (which
160
170
  // comes verbatim from the workflow asset's frontmatter and is therefore
161
171
  // attacker-influenceable). Keeping raw titles out of the events stream
@@ -163,7 +173,7 @@ export async function startWorkflowRun(ref, params = {}, options) {
163
173
  // into agent context.
164
174
  appendEvent({
165
175
  eventType: "workflow_started",
166
- ref: ref,
176
+ ref: asset.ref,
167
177
  metadata: { runId: result.run.id, status: result.run.status },
168
178
  });
169
179
  return result;
@@ -179,9 +189,9 @@ export async function getWorkflowStatus(runId, opts) {
179
189
  // project each row, INCLUDING failures whose diagnostic text the
180
190
  // deterministic evidence graph drops. Read-only; never mutates the run.
181
191
  const rows = repo.getUnitsForRun(run.id);
182
- // Codex round-3 finding B: run the SAME pure stale-claim evaluator `brief`
183
- // uses (`now` injected for deterministic tests) so a dead driver's claimed
184
- // `running` unit surfaces as stale here too, not just as raw `running`.
192
+ // Codex round-3 finding B: run the pure stale-claim evaluator (`now`
193
+ // injected for deterministic tests) so a unit left `running` by a process
194
+ // that died surfaces as stale here, not just as raw `running`.
185
195
  const staleById = new Map(evaluateStaleUnits(rows, opts.now ?? Date.now()).map((u) => [u.unitId, u]));
186
196
  const classified = classifyWorkflowRunPlan(run);
187
197
  const engines = classified.support === "supported" ? classified.plan.execution?.engines : undefined;
@@ -194,36 +204,60 @@ export async function hasWorkflowRun(runId) {
194
204
  return withWorkflowRunsRepo((repo) => repo.hasRun(runId));
195
205
  }
196
206
  export async function listWorkflowRuns(input) {
197
- return withWorkflowRunsRepo((repo) => {
198
- const scopeKey = getCurrentWorkflowScopeKey();
199
- let workflowRef;
200
- if (input?.workflowRef) {
201
- const parsed = parseWorkflowRefInput(input.workflowRef);
202
- if (parsed.type !== "workflow") {
203
- throw new UsageError(`Expected a workflow ref (workflows/<name>), got "${input.workflowRef}".`);
204
- }
205
- workflowRef = canonicalWorkflowRunRef(parsed.origin, canonicalizeWorkflowName(parsed.name));
207
+ const scopeKey = getCurrentWorkflowScopeKey();
208
+ const activeOnly = input?.activeOnly === true;
209
+ if (input?.workflowRef === undefined) {
210
+ return withWorkflowRunsRepo((repo) => ({
211
+ runs: repo.listRuns({ scopeKey, ...(activeOnly ? { activeOnly: true } : {}) }).map(toWorkflowRunSummary),
212
+ }));
213
+ }
214
+ const exactRef = input.workflowRef.trim();
215
+ if (!exactRef) {
216
+ throw new UsageError("Workflow ref filter cannot be empty.", "INVALID_FLAG_VALUE");
217
+ }
218
+ const parsedExactRef = parseBundleRef(exactRef);
219
+ if (parsedExactRef.fragment !== undefined) {
220
+ throw new UsageError("Workflow ref filters do not accept fragments.", "INVALID_FLAG_VALUE");
221
+ }
222
+ let workflowRefs = [exactRef];
223
+ try {
224
+ const canonicalRef = await canonicalizeWorkflowSpecifier(exactRef);
225
+ workflowRefs = await workflowRunRefSet(canonicalRef, exactRef);
226
+ }
227
+ catch (error) {
228
+ if (parsedExactRef.bundle !== undefined) {
229
+ const exactRows = await withWorkflowRunsRepo((repo) => repo.listRuns({ scopeKey, workflowRef: exactRef }));
230
+ if (exactRows.length === 0)
231
+ throw error;
232
+ return {
233
+ runs: exactRows.filter((row) => !activeOnly || row.status === "active").map(toWorkflowRunSummary),
234
+ };
206
235
  }
207
- const rows = repo.listRuns({
208
- scopeKey,
209
- ...(workflowRef ? { workflowRef } : {}),
210
- ...(input?.activeOnly ? { activeOnly: true } : {}),
211
- });
212
- return { runs: rows.map(toWorkflowRunSummary) };
213
- });
236
+ if (!(error instanceof NotFoundError))
237
+ throw error;
238
+ }
239
+ return withWorkflowRunsRepo((repo) => ({
240
+ runs: repo
241
+ .listRuns({ scopeKey, workflowRefs, ...(activeOnly ? { activeOnly: true } : {}) })
242
+ .map(toWorkflowRunSummary),
243
+ }));
214
244
  }
215
- export async function getNextWorkflowStep(specifier, params) {
245
+ export async function getNextWorkflowStep(specifier, params, options) {
216
246
  return withWorkflowRunsRepo(async (repo) => {
217
- const { run, autoStarted } = await resolveRunSpecifier(repo, specifier, params);
247
+ const { run, autoStarted, startWarnings } = await resolveRunSpecifier(repo, specifier, params, options?.parameterFlags);
218
248
  const steps = readWorkflowRunSteps(repo, run.id);
219
249
  const plan = requireExecutableWorkflowPlan(run);
220
250
  assertWorkflowSpineMatchesPlan(plan, run, steps);
221
- return { ...projectNextResult(run, steps), ...(autoStarted ? { autoStarted: true } : {}) };
251
+ return {
252
+ ...projectNextResult(run, steps),
253
+ ...(autoStarted ? { autoStarted: true } : {}),
254
+ ...(startWarnings?.length ? { startWarnings } : {}),
255
+ };
222
256
  });
223
257
  }
224
258
  /**
225
259
  * Project a run row + its step rows into a {@link WorkflowNextResult}. The pure
226
- * read-shaping half of {@link getNextWorkflowStep}, extracted so the driver
260
+ * read-shaping half of {@link getNextWorkflowStep}, extracted so the run
227
261
  * snapshot below reproduces the exact same projection without re-running the
228
262
  * auto-start-capable {@link resolveRunSpecifier}.
229
263
  */
@@ -251,27 +285,6 @@ function projectNextResult(run, steps) {
251
285
  ...(checkin ? { checkin } : {}),
252
286
  };
253
287
  }
254
- /**
255
- * A consistent point-in-time snapshot of a run for the harness-neutral driver
256
- * protocol (PR #714 review round 2, #14). `brief`/`report` previously read the
257
- * spine (`getNextWorkflowStep`) and then, in a SEPARATE connection, the run row
258
- * + unit journal — so a concurrent `report`/`run`/manual completion could change
259
- * the active step BETWEEN the two reads, leaving the described work-list
260
- * inconsistent with the run row it was stamped against. This reads the run row,
261
- * its steps, AND its unit rows inside ONE transaction (one connection, one
262
- * snapshot) so all three agree. It never auto-starts — `runId` must already
263
- * resolve to a concrete run — because the driver protocol never mutates on read.
264
- */
265
- export async function snapshotRunForDriver(runId) {
266
- return withWorkflowRunsRepo((repo) => repo.transaction(() => {
267
- const run = readWorkflowRun(repo, runId);
268
- const steps = readWorkflowRunSteps(repo, run.id);
269
- const plan = requireExecutableWorkflowPlan(run);
270
- assertWorkflowSpineMatchesPlan(plan, run, steps);
271
- const units = repo.getUnitsForRun(run.id);
272
- return { next: projectNextResult(run, steps), run, units };
273
- }));
274
- }
275
288
  export async function resumeWorkflowRun(runId) {
276
289
  return withWorkflowRunsRepo((repo) => {
277
290
  const run = readWorkflowRun(repo, runId);
@@ -306,23 +319,24 @@ export async function resumeWorkflowRun(runId) {
306
319
  */
307
320
  export async function abandonWorkflowRun(runId) {
308
321
  return withWorkflowRunsRepo((repo) => {
309
- const run = readWorkflowRun(repo, runId);
310
- requireAbandonableWorkflowPlan(run);
311
- const classified = classifyWorkflowRunPlan(run);
312
- const existingSteps = readWorkflowRunSteps(repo, run.id);
313
- if (classified.support === "supported")
314
- assertWorkflowSpineMatchesPlan(classified.plan, run, existingSteps);
315
- if (run.status === "completed" || run.status === "failed") {
316
- throw new UsageError(`Workflow run ${run.id} is already ${run.status}.`);
317
- }
318
322
  const now = new Date().toISOString();
319
- repo.updateRunState({
320
- status: "failed",
321
- currentStepId: run.current_step_id,
322
- updatedAt: now,
323
- completedAt: now,
324
- checkinArmedAt: now,
325
- runId: run.id,
323
+ const run = repo.immediateTransaction((db) => {
324
+ const current = readWorkflowRun(repo, runId);
325
+ if (current.status === "completed" || current.status === "failed") {
326
+ throw new UsageError(`Workflow run ${current.id} is already ${current.status}.`);
327
+ }
328
+ if (!repo.markRunAbandoned(current.id, now)) {
329
+ throw new UsageError(`Workflow run ${current.id} is ${current.status} and cannot be abandoned.`);
330
+ }
331
+ insertEventOnce(db, {
332
+ eventType: "workflow_abandoned",
333
+ ts: now,
334
+ ref: current.workflow_ref,
335
+ metadata: { runId: current.id },
336
+ idempotencyKey: current.id,
337
+ idempotencyMetadataKey: "runId",
338
+ });
339
+ return current;
326
340
  });
327
341
  const updated = {
328
342
  ...run,
@@ -333,9 +347,6 @@ export async function abandonWorkflowRun(runId) {
333
347
  };
334
348
  const steps = readWorkflowRunSteps(repo, run.id);
335
349
  const detail = buildWorkflowRunDetail(updated, steps);
336
- // Same injectable-footprint rule as workflow_started (07 P1-B): ids and
337
- // status only, never the frontmatter-derived title.
338
- appendEvent({ eventType: "workflow_abandoned", ref: run.workflow_ref, metadata: { runId: run.id } });
339
350
  return detail;
340
351
  });
341
352
  }
@@ -371,15 +382,20 @@ export async function completeWorkflowStep(input) {
371
382
  if (input.status === "completed" && !summary) {
372
383
  throw new UsageError(`Completing step "${input.stepId}" requires a --summary describing the work done.`, "MISSING_REQUIRED_ARGUMENT");
373
384
  }
374
- // #506: validation gate — judge the summary against the step's
375
- // completionCriteria via the configured LLM. Fail-open when no criteria or no
376
- // judge. Only a well-formed `complete: false` blocks completion.
385
+ // #506: validation gate — a criteria-bearing step must have a frozen judge
386
+ // and receive an affirmative verdict before it can advance.
377
387
  if (input.status === "completed" && summary) {
378
388
  const criteria = preflight.stepPlan.gate.criteria;
389
+ if (input.signal?.aborted)
390
+ throw interruptionReason(input.signal);
379
391
  const judge = input.summaryJudge === undefined
380
- ? frozenSummaryJudge(preflight.plan, preflight.stepPlan.gate.judge)
392
+ ? frozenSummaryJudge(preflight.plan, preflight.stepPlan.gate.judge, input.signal)
381
393
  : input.summaryJudge;
382
- const verdict = await validateStepSummary({ stepTitle: preflight.stepPlan.title, completionCriteria: criteria, summary }, judge ?? undefined, { required: input.requireGate === true });
394
+ if (criteria.length > 0 && !judge) {
395
+ throw new ConfigError(`Workflow run ${input.runId} has completion criteria for step "${input.stepId}" but its frozen plan has no judge. ` +
396
+ "Set workflow.judgeEngine, abandon this run, and create a new one with `akm workflow run <ref>`.", "INVALID_CONFIG_FILE");
397
+ }
398
+ const verdict = await validateStepSummary({ stepTitle: preflight.stepPlan.title, completionCriteria: criteria, summary }, judge ?? undefined, input.signal);
383
399
  if (!verdict.complete) {
384
400
  // Re-arm the check-in so a subsequent stall is still nudged, but leave the
385
401
  // step pending and return corrective feedback instead of completing.
@@ -392,12 +408,11 @@ export async function completeWorkflowStep(input) {
392
408
  stepId: input.stepId,
393
409
  missing: verdict.missing,
394
410
  feedback: verdict.feedback ?? "The summary does not satisfy the step's completion criteria.",
395
- // A REQUIRED gate that could not be judged (finding A): the caller BLOCKS
396
- // rather than treating this as a normal, retryable gate rejection.
397
- ...(verdict.errored ? { errored: true } : {}),
398
411
  };
399
412
  }
400
413
  }
414
+ if (input.signal?.aborted)
415
+ throw interruptionReason(input.signal);
401
416
  return withWorkflowRunsRepo((repo) => {
402
417
  let updatedRun;
403
418
  let refreshedSteps = [];
@@ -423,6 +438,8 @@ export async function completeWorkflowStep(input) {
423
438
  if (run.current_step_id !== existing.step_id) {
424
439
  throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
425
440
  }
441
+ if (input.signal?.aborted)
442
+ throw interruptionReason(input.signal);
426
443
  const completedAt = new Date().toISOString();
427
444
  repo.updateStepCompletion({
428
445
  status: input.status,
@@ -472,34 +489,76 @@ export async function completeWorkflowStep(input) {
472
489
  return detail;
473
490
  });
474
491
  }
475
- async function resolveRunSpecifier(repo, specifier, params) {
492
+ async function resolveRunSpecifier(repo, specifier, params, parameterFlags) {
493
+ const hasParameters = (params && Object.keys(params).length > 0) || (parameterFlags?.length ?? 0) > 0;
476
494
  const explicitRun = repo.getRunById(specifier);
477
495
  if (explicitRun) {
478
- if (params && Object.keys(params).length > 0) {
479
- throw new UsageError(`--params can only be used when starting a new run from a workflow ref, not with an existing run id ("${specifier}")`);
496
+ if (hasParameters) {
497
+ throw new UsageError(`Workflow parameter flags can only be used when starting a new run, not with existing run id "${specifier}".`);
480
498
  }
481
499
  return { run: explicitRun, autoStarted: false };
482
500
  }
483
- // Run-id vs workflow-ref disambiguation: a run id is a bare token, while a
484
- // canonical `workflows/name` ref carries a `/`.
485
- if (!specifier.includes(":") && !specifier.includes("/")) {
486
- throw new NotFoundError(`Workflow run "${specifier}" not found.`, "WORKFLOW_NOT_FOUND");
501
+ const scopeKey = getCurrentWorkflowScopeKey();
502
+ const exactRef = specifier.trim();
503
+ const parsedExact = parseBundleRef(exactRef);
504
+ const qualifiedExact = parsedExact.bundle !== undefined && parsedExact.fragment === undefined;
505
+ const detached = qualifiedExact ? repo.getActiveRunRowForScope(exactRef, scopeKey) : undefined;
506
+ let ref;
507
+ try {
508
+ ref = await canonicalizeWorkflowSpecifier(specifier);
487
509
  }
488
- const parsed = parseWorkflowRefInput(specifier);
489
- if (parsed.type !== "workflow") {
490
- throw new UsageError(`Expected a workflow ref or workflow run id, got "${specifier}".`);
510
+ catch (error) {
511
+ if (detached) {
512
+ if (hasParameters) {
513
+ throw new UsageError(`Workflow parameter flags can only be set on a new run; ${specifier} is already active.`);
514
+ }
515
+ return { run: detached, autoStarted: false };
516
+ }
517
+ if (error instanceof NotFoundError && !specifier.includes(":") && !specifier.includes("/")) {
518
+ throw new NotFoundError(`Workflow run or workflow "${specifier}" not found.`, "WORKFLOW_NOT_FOUND");
519
+ }
520
+ throw error;
491
521
  }
492
- const ref = canonicalWorkflowRunRef(parsed.origin, canonicalizeWorkflowName(parsed.name));
493
- const scopeKey = getCurrentWorkflowScopeKey();
494
- const active = repo.getActiveRunRowForScope(ref, scopeKey);
522
+ const active = repo.getActiveRunRowForScope(await workflowRunRefSet(ref, exactRef), scopeKey);
495
523
  if (active) {
496
- if (params && Object.keys(params).length > 0) {
497
- throw new UsageError(`--params can only be set on a new run; ${ref} already has an active run`);
524
+ if (hasParameters) {
525
+ throw new UsageError(`Workflow parameter flags can only be set on a new run; ${ref} is already active.`);
498
526
  }
499
527
  return { run: active, autoStarted: false };
500
528
  }
501
- const started = await startWorkflowRun(ref, params ?? {});
502
- return { run: readWorkflowRun(repo, started.run.id), autoStarted: true };
529
+ const started = await startWorkflowRun(ref, params ?? {}, {
530
+ ...(parameterFlags !== undefined ? { parameterFlags } : {}),
531
+ });
532
+ return {
533
+ run: readWorkflowRun(repo, started.run.id),
534
+ autoStarted: true,
535
+ ...(started.warnings?.length ? { startWarnings: started.warnings } : {}),
536
+ };
537
+ }
538
+ function interruptionReason(signal) {
539
+ return signal.reason instanceof Error ? signal.reason : new Error("Workflow run interrupted.");
540
+ }
541
+ async function canonicalizeWorkflowSpecifier(specifier) {
542
+ return canonicalizeWorkflowRefInput(specifier);
543
+ }
544
+ async function workflowRunRefSet(canonicalRef, exactRef) {
545
+ const parsed = parseBundleRef(canonicalRef);
546
+ const refs = new Set([canonicalRef, exactRef.trim()]);
547
+ const exact = parseBundleRef(exactRef.trim());
548
+ if (exact.bundle === undefined) {
549
+ refs.add(parsed.conceptId);
550
+ }
551
+ else {
552
+ try {
553
+ if ((await canonicalizeWorkflowSpecifier(parsed.conceptId)) === canonicalRef)
554
+ refs.add(parsed.conceptId);
555
+ }
556
+ catch (error) {
557
+ if (!(error instanceof NotFoundError))
558
+ throw error;
559
+ }
560
+ }
561
+ return [...refs];
503
562
  }
504
563
  function readWorkflowRun(repo, runId) {
505
564
  const run = repo.getRunById(runId);
@@ -513,7 +572,7 @@ function readWorkflowRunSteps(repo, runId) {
513
572
  }
514
573
  function buildWorkflowRunDetail(run, steps) {
515
574
  // Review M1: `workflow status` (and every other detail-shaped response) now
516
- // evaluates the check-in, not just `workflow next`. Pure timestamp check —
575
+ // evaluates the check-in, not just `workflow run`. Pure timestamp check —
517
576
  // no background thread (see checkin.ts).
518
577
  const checkin = evaluateCheckin({
519
578
  status: run.status,
@@ -551,7 +610,7 @@ function toWorkflowRunSummary(run) {
551
610
  planIrVersion: plan.irVersion,
552
611
  executionSupport: plan.support,
553
612
  // Surface the engine lease (holder id + expiry — never workflow-authored
554
- // content) so `workflow next`/`status` show who is driving the run.
613
+ // content) so `workflow run`/`status` show who is driving the run.
555
614
  ...(run.engine_lease_holder && run.engine_lease_until
556
615
  ? { engineLease: { holder: run.engine_lease_holder, until: run.engine_lease_until } }
557
616
  : {}),
@@ -560,7 +619,7 @@ function toWorkflowRunSummary(run) {
560
619
  /**
561
620
  * Single-driver enforcement (R2 run lease): while a LIVE (unexpired) engine
562
621
  * lease is held, only the holding engine may advance the gate spine. Manual
563
- * `akm workflow complete` (no `leaseHolder`) — or a stale engine invocation
622
+ * A call with no `leaseHolder` — or a stale engine invocation
564
623
  * whose lease was claimed by another — is refused with the holder + expiry.
565
624
  * An EXPIRED lease never blocks: the engine that held it is presumed dead.
566
625
  */