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,140 +2,19 @@
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 workflow` command family. Extracted verbatim from src/cli.ts (WS6) so the
6
- * God Module shrinks; the `main.subCommands.workflow` key and every subcommand's
7
- * args/output shape are byte-identical. Handlers whose body is a plain
8
- * `runWithJsonErrors(...) + output(...)` are migrated to `defineJsonCommand`,
9
- * which emits the same JSON envelope (stdout/stderr/exit-code) as the inline
10
- * form. `workflow template` keeps a plain `defineCommand` because it writes the
11
- * template straight to stdout with no JSON envelope. The private helpers
12
- * `looksLikeWorkflowRunId` and `resolveWorkflowFilePath` move with the family.
5
+ * `akm workflow` command family. `run` is the canonical start/resume/execute
6
+ * surface; the former public `start`, `next`, and `complete` lifecycle is gone.
7
+ * Workflows are markdown-only; authoring uses `create --print` and validation
8
+ * uses `akm lint --type workflows`.
13
9
  */
14
- import { defineCommand } from "citty";
15
- import { getParsedInvocation } from "../cli/invocation.js";
16
10
  import { getStringArg } from "../cli/parse-args.js";
17
- import { defineJsonCommand, output, runWithJsonErrors } from "../cli/shared.js";
11
+ import { defineGroupCommand, defineJsonCommand, EXIT_CODES, output } from "../cli/shared.js";
18
12
  import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../core/asset/asset-create.js";
19
- import { parseRefInput } from "../core/asset/resolve-ref.js";
20
- import { loadConfig } from "../core/config/config.js";
21
13
  import { NotFoundError, UsageError } from "../core/errors.js";
22
14
  import { akmIndex } from "../indexer/indexer.js";
23
- import { resolveSourceEntries } from "../indexer/search/search-source.js";
24
- import { resolveSourcesForOrigin } from "../registry/origin-resolve.js";
25
- import { resolveAssetPath } from "../sources/resolve.js";
26
- import { createWorkflowAsset, formatWorkflowErrors, getWorkflowProgramTemplate, getWorkflowTemplate, validateWorkflowProgramSource, validateWorkflowSource, } from "../workflows/authoring/authoring.js";
27
- import { hasWorkflowSubcommand, parseWorkflowJsonObject, parseWorkflowStepState, WORKFLOW_STEP_STATES, } from "../workflows/cli.js";
28
- import { isWorkflowProgramPath } from "../workflows/program/project.js";
29
- import { abandonWorkflowRun, completeWorkflowStep, getNextWorkflowStep, getWorkflowStatus, listWorkflowRuns, resumeWorkflowRun, startWorkflowRun, } from "../workflows/runtime/runs.js";
30
- import { canonicalWorkflowRunRef } from "../workflows/runtime/workflow-asset-loader.js";
31
- const workflowStartCommand = defineJsonCommand({
32
- meta: {
33
- name: "start",
34
- description: "Start a new workflow run in the current working scope",
35
- },
36
- args: {
37
- ref: { type: "positional", description: "Workflow ref (workflows/<name>)", required: true },
38
- params: { type: "string", description: "Workflow parameters as a JSON object" },
39
- force: {
40
- type: "boolean",
41
- description: "Allow a parallel run when an active run already exists in this scope (#485)",
42
- default: false,
43
- },
44
- },
45
- async run({ args }) {
46
- const result = await startWorkflowRun(args.ref, parseWorkflowJsonObject(args.params, "--params"), {
47
- force: args.force === true,
48
- });
49
- output("workflow-start", result);
50
- },
51
- });
52
- const workflowNextCommand = defineJsonCommand({
53
- meta: {
54
- name: "next",
55
- description: "Show the next actionable workflow step in the current scope, auto-starting a run when passed a workflow ref",
56
- },
57
- args: {
58
- target: { type: "positional", description: "Workflow run id or workflow ref", required: true },
59
- params: { type: "string", description: "Workflow parameters as a JSON object (only for auto-started runs)" },
60
- },
61
- async run({ args }) {
62
- // `--dry-run` is intentionally NOT a declared arg (so it stays out of
63
- // --help). The guard reads it straight from the invocation singleton so
64
- // existing callers still get a clear, actionable error instead of a
65
- // generic "unknown flag" from citty.
66
- if (getParsedInvocation().hasFlag("--dry-run")) {
67
- throw new UsageError("`akm workflow next` does not support --dry-run. Remove the flag to start or resume a run.", "INVALID_FLAG_VALUE");
68
- }
69
- const parsedParams = args.params ? parseWorkflowJsonObject(args.params, "--params") : undefined;
70
- // If the target looks like a UUID-style run id (no `:` and matches the
71
- // run-id shape), short-circuit with a structured WORKFLOW_NOT_FOUND
72
- // error before the ref parser throws an unhelpful ref-parse error.
73
- if (looksLikeWorkflowRunId(args.target)) {
74
- const { hasWorkflowRun } = await import("../workflows/runtime/runs.js");
75
- if (!(await hasWorkflowRun(args.target))) {
76
- throw new NotFoundError(`Workflow run "${args.target}" not found.`, "WORKFLOW_NOT_FOUND", "Run `akm workflow list --active` to see runs.");
77
- }
78
- }
79
- const result = await getNextWorkflowStep(args.target, parsedParams);
80
- output("workflow-next", result);
81
- },
82
- });
83
- /**
84
- * Heuristic: a workflow run id is a UUID-shaped or hex-id-shaped string with
85
- * no `/` separator (canonical refs contain `workflows/<name>`). When this
86
- * matches we can give a much better
87
- * error than the ref parser's "Invalid asset type" failure.
88
- */
89
- function looksLikeWorkflowRunId(target) {
90
- if (target.includes(":"))
91
- return false;
92
- if (target.includes("/"))
93
- return false;
94
- // UUID v4-ish: 8-4-4-4-12 hex digits separated by dashes.
95
- if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(target))
96
- return true;
97
- // Bare hex/alphanumeric run ids of >=8 chars (covers shortened ids).
98
- if (/^[0-9a-z][0-9a-z_-]{7,}$/i.test(target) && /[0-9]/.test(target))
99
- return true;
100
- return false;
101
- }
102
- const workflowCompleteCommand = defineJsonCommand({
103
- meta: {
104
- name: "complete",
105
- description: "Update a workflow step state and persist notes/evidence",
106
- },
107
- args: {
108
- runId: { type: "positional", description: "Workflow run id", required: true },
109
- step: { type: "string", description: "Workflow step id", required: true },
110
- state: {
111
- type: "string",
112
- description: `Step state (default: completed). One of: ${WORKFLOW_STEP_STATES.join(", ")}.`,
113
- },
114
- notes: { type: "string", description: "Notes for the completed step" },
115
- summary: {
116
- type: "string",
117
- description: "Summary of work done (required when completing a step); validated against completion criteria",
118
- },
119
- evidence: { type: "string", description: "Evidence JSON object for the step" },
120
- },
121
- async run({ args }) {
122
- const result = await completeWorkflowStep({
123
- runId: args.runId,
124
- stepId: args.step,
125
- status: parseWorkflowStepState(args.state),
126
- notes: args.notes,
127
- summary: args.summary,
128
- evidence: args.evidence ? parseWorkflowJsonObject(args.evidence, "--evidence") : undefined,
129
- });
130
- if ("ok" in result && result.ok === false) {
131
- // Summary failed the completion-criteria validation gate (#506): the
132
- // step stays pending and the agent receives corrective feedback.
133
- output("workflow-complete-rejected", result);
134
- return;
135
- }
136
- output("workflow-complete", result);
137
- },
138
- });
15
+ import { assertWorkflowMarkdownName, createWorkflowAsset, getWorkflowTemplate } from "../workflows/authoring/authoring.js";
16
+ import { WORKFLOW_MAX_RETRIES, WORKFLOW_MAX_TIMEOUT_MS } from "../workflows/ir/schema.js";
17
+ import { abandonWorkflowRun, getWorkflowStatus, hasWorkflowRun, listWorkflowRuns, resumeWorkflowRun, } from "../workflows/runtime/runs.js";
139
18
  const workflowStatusCommand = defineJsonCommand({
140
19
  meta: {
141
20
  name: "status",
@@ -146,38 +25,33 @@ const workflowStatusCommand = defineJsonCommand({
146
25
  units: {
147
26
  type: "boolean",
148
27
  description: "Also list per-unit rows from the run journal (unit id, status, failure_reason, and any result/error " +
149
- "diagnostic text). Diagnostics only — step evidence stays deterministic and is unaffected (#22).",
28
+ "diagnostic text). Diagnostics only — step evidence stays deterministic and is unaffected.",
150
29
  default: false,
151
30
  },
152
31
  },
153
32
  async run({ args }) {
154
33
  const target = args.target;
155
34
  const includeUnits = args.units === true;
156
- // Check if target looks like a workflow ref
157
- const parsed = (() => {
158
- try {
159
- return parseRefInput(target);
160
- }
161
- catch {
162
- return null;
163
- }
164
- })();
165
- if (parsed?.type === "workflow") {
166
- const ref = canonicalWorkflowRunRef(parsed.origin, parsed.name);
167
- const { runs } = await listWorkflowRuns({ workflowRef: ref });
168
- if (runs.length === 0) {
169
- throw new NotFoundError(`No workflow runs found for ${ref}`, "WORKFLOW_NOT_FOUND");
170
- }
171
- const mostRecent = runs[0];
172
- if (!mostRecent)
173
- throw new NotFoundError(`No workflow runs found for ${ref}`, "WORKFLOW_NOT_FOUND");
174
- const result = await getWorkflowStatus(mostRecent.id, { includeUnits });
175
- output("workflow-status", result);
176
- }
177
- else {
35
+ if (await hasWorkflowRun(target)) {
178
36
  const result = await getWorkflowStatus(target, { includeUnits });
179
37
  output("workflow-status", result);
38
+ return;
39
+ }
40
+ let runs;
41
+ try {
42
+ ({ runs } = await listWorkflowRuns({ workflowRef: target }));
43
+ }
44
+ catch (error) {
45
+ if (!target.includes(":") && !target.includes("/")) {
46
+ throw new NotFoundError(`Workflow run "${target}" not found.`, "WORKFLOW_NOT_FOUND");
47
+ }
48
+ throw error;
180
49
  }
50
+ const mostRecent = runs[0];
51
+ if (!mostRecent)
52
+ throw new NotFoundError(`No workflow runs found for ${target}`, "WORKFLOW_NOT_FOUND");
53
+ const result = await getWorkflowStatus(mostRecent.id, { includeUnits });
54
+ output("workflow-status", result);
181
55
  },
182
56
  });
183
57
  const workflowListCommand = defineJsonCommand({
@@ -197,12 +71,12 @@ const workflowListCommand = defineJsonCommand({
197
71
  const workflowCreateCommand = defineJsonCommand({
198
72
  meta: {
199
73
  name: "create",
200
- description: "Create a workflow in the working stash (markdown document by default; a .yaml/.yml name writes a YAML program)",
74
+ description: "Create a workflow (markdown document) in the working bundle",
201
75
  },
202
76
  args: {
203
77
  name: {
204
78
  type: "positional",
205
- description: "Workflow name (flat, no '/'; use --path for a subdirectory). A .yaml/.yml suffix creates a YAML program.",
79
+ description: "Workflow name (flat, no '/'; use --path for a subdirectory).",
206
80
  required: true,
207
81
  },
208
82
  path: {
@@ -211,7 +85,7 @@ const workflowCreateCommand = defineJsonCommand({
211
85
  },
212
86
  from: {
213
87
  type: "string",
214
- description: "Import and validate content from an existing file (parsed per the destination extension)",
88
+ description: "Import and validate content from an existing file",
215
89
  },
216
90
  force: {
217
91
  type: "boolean",
@@ -223,6 +97,11 @@ const workflowCreateCommand = defineJsonCommand({
223
97
  description: "Explicitly replace an existing workflow with a fresh template (use with --force)",
224
98
  default: false,
225
99
  },
100
+ print: {
101
+ type: "boolean",
102
+ description: "Print the RAW template that would be written to stdout without creating anything — pipe it to a file as a starter document",
103
+ default: false,
104
+ },
226
105
  },
227
106
  async run({ args }) {
228
107
  // `name` is flat; subdirectory placement is `--path`'s job.
@@ -232,6 +111,14 @@ const workflowCreateCommand = defineJsonCommand({
232
111
  if (!namePattern.test(effectiveName)) {
233
112
  throw new UsageError("Workflow name must start with a lowercase letter or digit and contain only lowercase letters, digits, hyphens, dots, underscores, and slashes.");
234
113
  }
114
+ assertWorkflowMarkdownName(effectiveName);
115
+ if (args.print) {
116
+ // Raw document, not an envelope — the retired `workflow template` was
117
+ // format-exempt for the same reason: `--print > starter.md` must yield
118
+ // a usable starter file, not `{ok,template,kind}` JSON.
119
+ process.stdout.write(getWorkflowTemplate());
120
+ return;
121
+ }
235
122
  if (args.force && !args.from && !args.reset) {
236
123
  throw new UsageError("Refusing to overwrite with template: pass --from <file> to replace content, or --reset to explicitly replace with a fresh template.");
237
124
  }
@@ -240,312 +127,159 @@ const workflowCreateCommand = defineJsonCommand({
240
127
  from: args.from,
241
128
  force: args.force,
242
129
  });
243
- // Index the newly-written workflow so `akm workflow start` can resolve
130
+ // Index the newly-written workflow so `akm workflow run` can resolve
244
131
  // a workflowEntryId without requiring an explicit `akm index` call
245
132
  // first. Uses the same incremental index path that `akm add` uses.
246
133
  await akmIndex({ stashDir: result.stashDir });
247
134
  output("workflow-create", { ok: true, ...result });
248
135
  },
249
136
  });
250
- const workflowTemplateCommand = defineCommand({
251
- meta: {
252
- name: "template",
253
- description: "Print a valid workflow template (markdown by default, --yaml for a YAML program)",
254
- },
255
- args: {
256
- yaml: {
257
- type: "boolean",
258
- description: "Print a minimal valid YAML workflow program instead of the markdown template",
259
- default: false,
260
- },
261
- },
262
- run({ args }) {
263
- process.stdout.write(args.yaml ? getWorkflowProgramTemplate() : getWorkflowTemplate());
264
- },
265
- });
266
- const workflowValidateCommand = defineJsonCommand({
267
- meta: {
268
- name: "validate",
269
- description: "Validate a workflow file or ref (markdown document or YAML program) and print any errors",
270
- },
271
- args: {
272
- target: {
273
- type: "positional",
274
- description: "Workflow ref (workflows/<name>) or filesystem path to a workflow .md/.yaml",
275
- required: true,
276
- },
277
- },
278
- async run({ args }) {
279
- const filePath = await resolveWorkflowFilePath(args.target);
280
- // YAML programs (redesign addendum, R1) validate through the program
281
- // parser AND compiler so expression/reference errors surface at lint
282
- // time; both error lists carry line numbers. Markdown is unchanged.
283
- if (isWorkflowProgramPath(filePath)) {
284
- const { result } = validateWorkflowProgramSource(filePath);
285
- if (!result.ok) {
286
- throw new UsageError(formatWorkflowErrors(filePath, result.errors));
287
- }
288
- // Non-fatal WARNINGS ride the envelope additively — `ok` stays true. The
289
- // text formatter renders them clearly marked for humans; the JSON key is
290
- // the machine channel. Empty array when the program is fully typed/declared.
291
- output("workflow-validate", {
292
- ok: true,
293
- path: filePath,
294
- format: "program",
295
- title: result.program.name,
296
- stepCount: result.program.steps.length,
297
- warnings: result.warnings.map((w) => ({ line: w.line, message: w.message })),
298
- });
299
- return;
300
- }
301
- const { parse } = validateWorkflowSource(filePath);
302
- if (parse.ok) {
303
- output("workflow-validate", {
304
- ok: true,
305
- path: filePath,
306
- title: parse.document.title,
307
- stepCount: parse.document.steps.length,
308
- });
309
- return;
310
- }
311
- throw new UsageError(formatWorkflowErrors(filePath, parse.errors));
312
- },
313
- });
314
- async function resolveWorkflowFilePath(target) {
315
- // Canonical workflow refs resolve through the source search; anything else is
316
- // treated as a filesystem path.
317
- const looksLikeWorkflowRef = target.startsWith("workflows/") || target.includes("//workflows/");
318
- if (!looksLikeWorkflowRef)
319
- return target;
320
- const parsed = parseRefInput(target);
321
- if (parsed.type !== "workflow") {
322
- throw new UsageError(`Expected a workflow ref (workflows/<name>), got "${target}".`);
323
- }
324
- const config = loadConfig();
325
- const allSources = resolveSourceEntries(undefined, config);
326
- const searchSources = resolveSourcesForOrigin(parsed.origin, allSources);
327
- for (const source of searchSources) {
328
- try {
329
- return await resolveAssetPath(source.path, "workflow", parsed.name);
330
- }
331
- catch {
332
- /* try next source */
333
- }
334
- }
335
- throw new UsageError(`Workflow not found for ref: workflows/${parsed.name}`);
336
- }
337
137
  const workflowRunCommand = defineJsonCommand({
338
138
  meta: {
339
139
  name: "run",
340
- description: "EXPERIMENTAL: execute a workflow's steps with the native engine akm dispatches each step's units " +
341
- "(fan-out, schema output) to the configured runner and advances the run through the normal completion gates",
140
+ description: "Start or resume a workflow and execute it through completion, failure, a verification gate, or an explicit limit",
342
141
  },
343
142
  args: {
344
143
  target: { type: "positional", description: "Workflow run id or workflow ref (auto-starts a run)", required: true },
345
- params: { type: "string", description: "Workflow parameters as a JSON object (only for auto-started runs)" },
346
144
  "max-steps": { type: "string", description: "Stop after executing this many steps" },
347
- "require-gates": {
348
- type: "boolean",
349
- description: "Treat every criteria-bearing completion gate as required: if no LLM judge is available, BLOCK the step " +
350
- "(for a human to resolve via `akm workflow resume`) instead of failing open. A per-step `gate.required: true` " +
351
- "in the workflow does the same on every surface; this is the run-wide override (#18).",
352
- default: false,
353
- },
145
+ "max-retries": { type: "string", description: "Retry a failed workflow step this many additional times" },
146
+ timeout: { type: "string", description: "Whole-run timeout: N, Nms, Ns, or Nm (bare N is milliseconds)" },
354
147
  },
355
- async run({ args }) {
148
+ async run({ args, rawArgs }) {
356
149
  const { runWorkflowSteps } = await import("../workflows/exec/run-workflow.js");
357
- const rawMaxSteps = getStringArg(args, "max-steps");
358
- let maxSteps;
359
- if (rawMaxSteps !== undefined) {
360
- maxSteps = Number.parseInt(rawMaxSteps, 10);
361
- if (!/^\d+$/.test(rawMaxSteps) || maxSteps <= 0) {
362
- throw new UsageError(`--max-steps must be a positive integer, got "${rawMaxSteps}".`, "INVALID_FLAG_VALUE");
150
+ const parameterFlags = parseWorkflowParameterFlags(rawArgs, args.target);
151
+ const maxSteps = parseIntegerFlag(getStringArg(args, "max-steps"), "--max-steps", 1);
152
+ const maxRetries = parseIntegerFlag(getStringArg(args, "max-retries"), "--max-retries", 0, WORKFLOW_MAX_RETRIES);
153
+ const timeoutMs = parseWorkflowTimeout(getStringArg(args, "timeout"));
154
+ const controller = new AbortController();
155
+ let timedOut = false;
156
+ let signalExitCode;
157
+ const interrupt = (signal) => {
158
+ signalExitCode = signal === "SIGINT" ? 130 : 143;
159
+ controller.abort(new Error(`Workflow run interrupted by ${signal}.`));
160
+ };
161
+ const onSigint = () => interrupt("SIGINT");
162
+ const onSigterm = () => interrupt("SIGTERM");
163
+ process.once("SIGINT", onSigint);
164
+ process.once("SIGTERM", onSigterm);
165
+ const timer = timeoutMs === undefined
166
+ ? undefined
167
+ : setTimeout(() => {
168
+ timedOut = true;
169
+ controller.abort(new Error(`Workflow run timed out after ${timeoutMs}ms.`));
170
+ }, timeoutMs);
171
+ timer?.unref?.();
172
+ try {
173
+ const result = await runWorkflowSteps({
174
+ target: args.target,
175
+ parameterFlags,
176
+ ...(maxSteps !== undefined ? { maxSteps } : {}),
177
+ ...(maxRetries !== undefined ? { maxRetries } : {}),
178
+ signal: controller.signal,
179
+ });
180
+ const rendered = { ...result, ...(timedOut ? { timedOut: true } : {}) };
181
+ output("workflow-run", rendered);
182
+ if (result.run.status === "failed" || result.gateRejection || result.aborted) {
183
+ process.exitCode = signalExitCode ?? EXIT_CODES.GENERAL;
363
184
  }
364
185
  }
365
- const result = await runWorkflowSteps({
366
- target: args.target,
367
- ...(args.params ? { params: parseWorkflowJsonObject(args.params, "--params") } : {}),
368
- ...(maxSteps !== undefined ? { maxSteps } : {}),
369
- ...(args["require-gates"] === true ? { requireGates: true } : {}),
370
- });
371
- output("workflow-run", result);
372
- },
373
- });
374
- const workflowBriefCommand = defineJsonCommand({
375
- meta: {
376
- name: "brief",
377
- description: "EXPERIMENTAL: describe a run's active step as an executable work-list for ANY agent session (the " +
378
- "harness-neutral driver protocol) — read-only, takes no engine lease, mutates nothing; prints per-unit " +
379
- "instructions, output schema, env binding names, and the exact `akm workflow report` command lines",
380
- },
381
- args: {
382
- target: {
383
- type: "positional",
384
- description: "Workflow run id (or a workflow ref with an active run)",
385
- required: true,
386
- },
387
- },
388
- async run({ args }) {
389
- const { buildWorkflowBrief } = await import("../workflows/exec/brief.js");
390
- const result = await buildWorkflowBrief(args.target);
391
- output("workflow-brief", result);
186
+ finally {
187
+ if (timer)
188
+ clearTimeout(timer);
189
+ process.off("SIGINT", onSigint);
190
+ process.off("SIGTERM", onSigterm);
191
+ }
392
192
  },
393
193
  });
394
- const WORKFLOW_REPORT_STATES = ["completed", "failed", "running"];
395
- const workflowReportCommand = defineJsonCommand({
396
- meta: {
397
- name: "report",
398
- description: "EXPERIMENTAL: report a unit's result back into a run (the mutating half of the harness-neutral driver " +
399
- "protocol) — ingested through the SAME shared step semantics the engine uses. --status running claims/" +
400
- "heartbeats a unit; completed/failed records it and, when the step's work-list is fully terminal, runs the " +
401
- "engine's completion path (reducer, artifact + schema validation, gate). --settle (no --unit) advances a run " +
402
- "parked on a route-only/empty step. Refused while a live engine lease exists",
403
- },
404
- args: {
405
- target: {
406
- type: "positional",
407
- description: "Workflow run id (or a workflow ref with an active run)",
408
- required: true,
409
- },
410
- unit: {
411
- type: "string",
412
- description: "Content-derived unit id from `akm workflow brief` (copy it verbatim). Omit with --settle.",
413
- },
414
- settle: {
415
- type: "boolean",
416
- description: "Advance/finalize a run whose active step has NO unit left to report: a non-dispatching step (params-based route, empty fan-out, all-unresolvable) OR a fully-terminal step still needing finalization (every unit ran but the gate never judged — e.g. after resuming a required-gate block). Runs the deterministic completion path. Mutually exclusive with --unit; refused when the step still has genuinely pending units",
417
- default: false,
418
- },
419
- "expect-step": {
420
- type: "string",
421
- description: "Guard: the step id you briefed against. Refuses the report if the run's active step has since moved (from the `brief` report/settle command line)",
422
- },
423
- status: { type: "string", description: `Unit status: ${WORKFLOW_REPORT_STATES.join(", ")}` },
424
- result: { type: "string", description: "Result payload (JSON for a schema unit, else text). completed only." },
425
- "result-file": { type: "string", description: "Read the result payload from this file instead of --result/stdin" },
426
- tokens: { type: "string", description: "Tokens spent on this unit (counts against a declared budget)" },
427
- "session-id": { type: "string", description: "Harness-native session id revealed while executing the unit" },
428
- "failure-reason": { type: "string", description: "Structured failure vocabulary for a --status failed report" },
429
- note: { type: "string", description: "Short progress note for a --status running heartbeat (not persisted)" },
430
- rerun: {
431
- type: "boolean",
432
- description: "Re-run an already-FAILED unit: record a NEW attempt (re-applies budget) instead of refusing a differing re-report",
433
- default: false,
434
- },
435
- },
436
- async run({ args }) {
437
- // --settle: the unit-less verb that advances a run parked on a
438
- // non-dispatching step. Mutually exclusive with the per-unit report flags.
439
- if (args.settle === true) {
440
- if (getStringArg(args, "unit") !== undefined || getStringArg(args, "status") !== undefined) {
441
- throw new UsageError("--settle advances a route-only/empty step and takes no --unit or --status. Drop them, or report a " +
442
- "specific unit with `--unit <id> --status <state>` instead.", "INVALID_FLAG_VALUE");
194
+ const WORKFLOW_RUN_VALUE_FLAGS = new Set([
195
+ "max-steps",
196
+ "maxSteps",
197
+ "max-retries",
198
+ "maxRetries",
199
+ "timeout",
200
+ "format",
201
+ "detail",
202
+ "shape",
203
+ "output",
204
+ ]);
205
+ const WORKFLOW_RUN_BOOLEAN_FLAGS = new Set(["quiet", "verbose", "help", "no-quiet", "no-verbose"]);
206
+ export function parseWorkflowParameterFlags(rawArgs, target) {
207
+ const flags = [];
208
+ let targetSeen = false;
209
+ for (let index = 0; index < rawArgs.length; index += 1) {
210
+ const token = rawArgs[index];
211
+ if (token === "--") {
212
+ throw new UsageError("`akm workflow run` does not accept positional arguments after `--`.", "INVALID_FLAG_VALUE");
213
+ }
214
+ if (!token.startsWith("-") || token === "-" || /^-\d/.test(token)) {
215
+ if (!targetSeen) {
216
+ if (token !== target) {
217
+ throw new UsageError("Workflow parameter flags must come after the workflow ref or run id.", "INVALID_FLAG_VALUE");
218
+ }
219
+ targetSeen = true;
220
+ continue;
443
221
  }
444
- const { settleWorkflowSpine } = await import("../workflows/exec/report.js");
445
- const result = await settleWorkflowSpine({
446
- target: args.target,
447
- ...(getStringArg(args, "expect-step") !== undefined ? { expectStep: getStringArg(args, "expect-step") } : {}),
448
- });
449
- output("workflow-report", result);
450
- return;
222
+ throw new UsageError(`Unexpected positional workflow argument "${token}".`, "INVALID_FLAG_VALUE");
451
223
  }
452
- const status = args.status;
453
- if (!status) {
454
- throw new UsageError("--status is required (completed | failed | running), or pass --settle to advance a non-dispatching step.", "MISSING_REQUIRED_ARGUMENT");
224
+ if (!token.startsWith("--"))
225
+ continue;
226
+ const body = token.slice(2);
227
+ const equalsAt = body.indexOf("=");
228
+ const name = equalsAt === -1 ? body : body.slice(0, equalsAt);
229
+ const inlineValue = equalsAt === -1 ? undefined : body.slice(equalsAt + 1);
230
+ if (name === "params") {
231
+ throw new UsageError("--params was removed. Pass each declared workflow parameter as its own flag, for example `--version=1.2.3`.", "INVALID_FLAG_VALUE");
455
232
  }
456
- if (!WORKFLOW_REPORT_STATES.includes(status)) {
457
- throw new UsageError(`Invalid --status "${status}". Expected one of: ${WORKFLOW_REPORT_STATES.join(", ")}.`, "INVALID_FLAG_VALUE");
233
+ if (WORKFLOW_RUN_VALUE_FLAGS.has(name)) {
234
+ if (inlineValue === undefined)
235
+ index += 1;
236
+ continue;
458
237
  }
459
- const unitId = getStringArg(args, "unit");
460
- if (!unitId) {
461
- throw new UsageError("--unit is required (the content-derived unit id from `akm workflow brief`), or pass --settle for a route-only/empty step.", "MISSING_REQUIRED_ARGUMENT");
238
+ if (WORKFLOW_RUN_BOOLEAN_FLAGS.has(name))
239
+ continue;
240
+ if (!targetSeen) {
241
+ throw new UsageError("Workflow parameter flags must come after the workflow ref or run id.", "INVALID_FLAG_VALUE");
462
242
  }
463
- let tokens;
464
- const rawTokens = getStringArg(args, "tokens");
465
- if (rawTokens !== undefined) {
466
- tokens = Number.parseInt(rawTokens, 10);
467
- if (!/^\d+$/.test(rawTokens)) {
468
- throw new UsageError(`--tokens must be a non-negative integer, got "${rawTokens}".`, "INVALID_FLAG_VALUE");
469
- }
243
+ if (inlineValue !== undefined) {
244
+ flags.push({ name, value: inlineValue });
245
+ continue;
470
246
  }
471
- // Result payload precedence: --result, then --result-file, then stdin
472
- // (completed/failed only; a running heartbeat carries no result).
473
- let resultRaw;
474
- if (status !== "running") {
475
- const resultFile = getStringArg(args, "result-file");
476
- if (args.result !== undefined && resultFile !== undefined) {
477
- throw new UsageError("Pass at most one of --result or --result-file.", "INVALID_FLAG_VALUE");
478
- }
479
- if (args.result !== undefined) {
480
- resultRaw = String(args.result);
481
- }
482
- else if (resultFile !== undefined) {
483
- const fs = await import("node:fs");
484
- resultRaw = fs.readFileSync(resultFile, "utf8");
485
- }
486
- else if (!process.stdin.isTTY) {
487
- resultRaw = await readStdin();
488
- }
247
+ const next = rawArgs[index + 1];
248
+ if (next !== undefined && (!next.startsWith("-") || /^-\d/.test(next))) {
249
+ flags.push({ name, value: next });
250
+ index += 1;
489
251
  }
490
- const { reportWorkflowUnit } = await import("../workflows/exec/report.js");
491
- const result = await reportWorkflowUnit({
492
- target: args.target,
493
- unitId,
494
- status: status,
495
- ...(getStringArg(args, "expect-step") !== undefined ? { expectStep: getStringArg(args, "expect-step") } : {}),
496
- ...(resultRaw !== undefined ? { resultRaw } : {}),
497
- ...(tokens !== undefined ? { tokens } : {}),
498
- ...(args.rerun === true ? { rerun: true } : {}),
499
- ...(getStringArg(args, "session-id") !== undefined ? { sessionId: getStringArg(args, "session-id") } : {}),
500
- ...(getStringArg(args, "failure-reason") !== undefined
501
- ? { failureReason: getStringArg(args, "failure-reason") }
502
- : {}),
503
- ...(getStringArg(args, "note") !== undefined ? { note: getStringArg(args, "note") } : {}),
504
- });
505
- output("workflow-report", result);
506
- },
507
- });
508
- async function readStdin() {
509
- const chunks = [];
510
- for await (const chunk of process.stdin)
511
- chunks.push(chunk);
512
- return Buffer.concat(chunks).toString("utf8");
513
- }
514
- const workflowWatchCommand = defineJsonCommand({
515
- meta: {
516
- name: "watch",
517
- description: "Print a run's workflow_* events (state.db events table) as NDJSON and exit; --stream polls in the " +
518
- "foreground until the run reaches a terminal status (no daemon)",
519
- },
520
- args: {
521
- runId: { type: "positional", description: "Workflow run id", required: true },
522
- stream: {
523
- type: "boolean",
524
- description: "Keep polling for new events until the run leaves 'active' (completed/failed/blocked)",
525
- default: false,
526
- },
527
- "interval-ms": { type: "string", description: "Poll interval in milliseconds for --stream (default: 1000)" },
528
- },
529
- async run({ args }) {
530
- const rawInterval = getStringArg(args, "interval-ms");
531
- let intervalMs;
532
- if (rawInterval !== undefined) {
533
- intervalMs = Number.parseInt(rawInterval, 10);
534
- if (!/^\d+$/.test(rawInterval) || intervalMs <= 0) {
535
- throw new UsageError(`--interval-ms must be a positive integer, got "${rawInterval}".`, "INVALID_FLAG_VALUE");
536
- }
252
+ else {
253
+ flags.push({ name, value: true });
537
254
  }
538
- const { watchWorkflowRun } = await import("../workflows/exec/watch.js");
539
- const result = await watchWorkflowRun({
540
- runId: args.runId,
541
- stream: args.stream === true,
542
- ...(intervalMs !== undefined ? { intervalMs } : {}),
543
- });
544
- // The event lines above are raw NDJSON on stdout; this trailing envelope
545
- // is the machine-readable command result (counts + terminal status).
546
- output("workflow-watch", { ok: true, ...result });
547
- },
548
- });
255
+ }
256
+ return flags;
257
+ }
258
+ function parseIntegerFlag(raw, name, minimum, maximum) {
259
+ if (raw === undefined)
260
+ return undefined;
261
+ const value = Number.parseInt(raw, 10);
262
+ if (!/^\d+$/.test(raw) || value < minimum || (maximum !== undefined && value > maximum)) {
263
+ const range = maximum === undefined ? `at least ${minimum}` : `from ${minimum} through ${maximum}`;
264
+ throw new UsageError(`${name} must be an integer ${range}, got "${raw}".`, "INVALID_FLAG_VALUE");
265
+ }
266
+ return value;
267
+ }
268
+ function parseWorkflowTimeout(raw) {
269
+ if (raw === undefined)
270
+ return undefined;
271
+ const match = /^(\d+)(ms|s|m)?$/.exec(raw);
272
+ if (!match) {
273
+ throw new UsageError(`--timeout must be N, Nms, Ns, or Nm, got "${raw}".`, "INVALID_FLAG_VALUE");
274
+ }
275
+ const amount = Number(match[1]);
276
+ const multiplier = match[2] === "m" ? 60_000 : match[2] === "s" ? 1_000 : 1;
277
+ const timeoutMs = amount * multiplier;
278
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > WORKFLOW_MAX_TIMEOUT_MS) {
279
+ throw new UsageError(`--timeout must resolve to 1 through ${WORKFLOW_MAX_TIMEOUT_MS} milliseconds, got "${raw}".`, "INVALID_FLAG_VALUE");
280
+ }
281
+ return timeoutMs;
282
+ }
549
283
  const workflowAbandonCommand = defineJsonCommand({
550
284
  meta: {
551
285
  name: "abandon",
@@ -572,32 +306,23 @@ const workflowResumeCommand = defineJsonCommand({
572
306
  output("workflow-resume", result);
573
307
  },
574
308
  });
575
- export const workflowCommand = defineCommand({
309
+ export const workflowCommand = defineGroupCommand({
576
310
  meta: {
577
311
  name: "workflow",
578
312
  description: "Author, inspect, and execute step-by-step workflow assets",
579
313
  },
580
314
  subCommands: {
581
- start: workflowStartCommand,
582
- next: workflowNextCommand,
583
- complete: workflowCompleteCommand,
584
315
  status: workflowStatusCommand,
585
316
  list: workflowListCommand,
586
317
  create: workflowCreateCommand,
587
- template: workflowTemplateCommand,
588
318
  resume: workflowResumeCommand,
589
319
  abandon: workflowAbandonCommand,
590
- validate: workflowValidateCommand,
591
320
  run: workflowRunCommand,
592
- brief: workflowBriefCommand,
593
- report: workflowReportCommand,
594
- watch: workflowWatchCommand,
595
- },
596
- run({ args }) {
597
- return runWithJsonErrors(async () => {
598
- if (hasWorkflowSubcommand(args))
599
- return;
600
- output("workflow-list", await listWorkflowRuns({ activeOnly: true }));
601
- });
602
321
  },
322
+ // No `defaultRun`: bare `akm workflow` is a usage error (exit 2), the
323
+ // canonical bare-group behavior — owner ruling 12. Run `akm workflow list
324
+ // --active` for what the bare form used to print. This group was previously
325
+ // hand-rolled on `defineCommand` with its own `hasWorkflowSubcommand` guard,
326
+ // which duplicated the subcommand names in a second hand-maintained set;
327
+ // `defineGroupCommand` derives the guard from `subCommands` directly.
603
328
  });