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
@@ -5,27 +5,41 @@ import path from "node:path";
5
5
  import { deepMergeConfig } from "../../core/config/deep-merge.js";
6
6
  import { ConfigError, UsageError } from "../../core/errors.js";
7
7
  import { DEFAULT_AGENT_TIMEOUT_MS, DEFAULT_LLM_TIMEOUT_MS } from "../../integrations/agent/config.js";
8
+ import { FALLBACK_ANNOUNCEMENT, NO_ENGINE_MESSAGE_SUFFIX, NO_ENGINE_REMEDY, withEngineFallback, } from "../../integrations/agent/engine-fallback.js";
8
9
  import { resolveLlmEngineUse, } from "../../integrations/agent/engine-resolution.js";
9
10
  import { resolveLlmModel, resolveModel } from "../../integrations/agent/model-aliases.js";
10
11
  import { getBuiltinAgentProfile } from "../../integrations/agent/profiles.js";
11
12
  import { HARNESS_BY_ID } from "../../integrations/harnesses/index.js";
12
13
  import { workflowMaxConcurrency } from "../concurrency-policy.js";
13
- import { compileWorkflowPlan, compileWorkflowProgram, } from "./compile.js";
14
+ import { compileWorkflowPlan } from "./compile.js";
14
15
  import { decodeWorkflowPlanV3, WORKFLOW_IR_VERSION } from "./schema.js";
15
16
  /**
16
17
  * The only source-to-runtime boundary. Source compilation remains pure; engine
17
18
  * selection and every dispatch-significant setting are resolved here once.
18
19
  */
19
- export function compileResolveFreezeWorkflow(asset, config) {
20
- const preliminary = asset.program ? compileProgram(asset) : compileMarkdown(asset);
20
+ export function compileResolveFreezeWorkflow(asset, inputConfig) {
21
+ // Applied ONCE, before any resolution: every engine lookup below (selection,
22
+ // snapshots, the gate judge) then sees one config and needs no fallback
23
+ // awareness of its own.
24
+ const { config, fallbackEngineName } = withEngineFallback(inputConfig);
25
+ // Announce only if the fallback candidate is what a unit actually froze to:
26
+ // `defaults.engine` is the lowest-precedence selector, so a document- or
27
+ // unit-level `engine:` still wins and must not be reported as opencode's.
28
+ let usedFallbackEngine = false;
29
+ const preliminary = compilePlan(asset);
21
30
  const engines = {};
22
31
  const maxConcurrency = frozenConcurrency(config);
23
- const programDefaults = asset.program?.defaults;
32
+ const documentDefaults = asset.document.defaults;
24
33
  const freezeInvocation = (unit) => {
25
- const layers = [...(programDefaults ? [programDefaults] : []), ...(unit ? [unit] : [])];
34
+ const layers = [...(documentDefaults ? [documentDefaults] : []), ...(unit ? [unit] : [])];
26
35
  const name = selectedEngine(config, layers);
27
36
  if (!name)
28
- throw new ConfigError("No workflow engine is selected. Set defaults.engine or workflow defaults.engine.", "INVALID_CONFIG_FILE");
37
+ throw new ConfigError(
38
+ // Reached only when the implicit opencode-sdk fallback did not apply
39
+ // either, so the remedy names both routes.
40
+ `This workflow ${NO_ENGINE_MESSAGE_SUFFIX} Set defaults.engine or workflow defaults.engine.`, "INVALID_CONFIG_FILE", NO_ENGINE_REMEDY);
41
+ if (name === fallbackEngineName)
42
+ usedFallbackEngine = true;
29
43
  const engine = engineDefinition(config, name);
30
44
  addSnapshot(config, name, engines);
31
45
  const model = exactModel(config, name, engine, layers);
@@ -41,6 +55,7 @@ export function compileResolveFreezeWorkflow(asset, config) {
41
55
  id: node.id,
42
56
  instructions: node.instructions,
43
57
  templating: node.templating ?? "verbatim",
58
+ ...(node.inputs && node.inputs.length > 0 ? { inputs: node.inputs } : {}),
44
59
  invocation: freezeInvocation(unit),
45
60
  ...(node.schema ? { schema: node.schema } : {}),
46
61
  ...(node.retry ? { retry: node.retry } : {}),
@@ -50,8 +65,8 @@ export function compileResolveFreezeWorkflow(asset, config) {
50
65
  ...(node.source ? { source: node.source } : {}),
51
66
  });
52
67
  const steps = preliminary.steps.map((step, index) => {
53
- const sourceStep = asset.program?.steps[index];
54
- const sourceUnit = sourceStep?.unit ?? sourceStep?.map?.unit;
68
+ const sourceStep = asset.document.steps[index];
69
+ const sourceUnit = sourceStep?.map ? sourceStep.map.unit : sourceStep?.unit;
55
70
  const root = step.root
56
71
  ? step.root.kind === "map"
57
72
  ? {
@@ -66,14 +81,13 @@ export function compileResolveFreezeWorkflow(asset, config) {
66
81
  : freezeUnit(step.root, sourceUnit)
67
82
  : undefined;
68
83
  const criteria = step.gate.criteria;
69
- const judge = criteria.length === 0 ? null : freezeGateJudge(config, engines, step.gate.required === true);
84
+ const judge = criteria.length === 0 ? null : freezeGateJudge(config, engines);
70
85
  const gate = {
71
86
  kind: "gate",
72
87
  id: `${step.stepId}.gate`,
73
88
  stepId: step.stepId,
74
89
  criteria,
75
90
  maxLoops: step.gate.maxLoops ?? 1,
76
- required: step.gate.required === true,
77
91
  judge,
78
92
  };
79
93
  return {
@@ -95,24 +109,21 @@ export function compileResolveFreezeWorkflow(asset, config) {
95
109
  execution: { maxConcurrency, engines },
96
110
  steps,
97
111
  });
112
+ // `usedFallbackEngine` IS the candidate-won predicate, so use the constant
113
+ // directly rather than re-asking a helper to compare a name with itself.
114
+ const engineAnnouncement = usedFallbackEngine ? FALLBACK_ANNOUNCEMENT : undefined;
98
115
  return {
99
- warnings: asset.program ? preliminary.warnings : [],
116
+ warnings: preliminary.warnings,
117
+ ...(engineAnnouncement ? { engineAnnouncement } : {}),
100
118
  plan,
101
119
  };
102
120
  }
103
- function compileProgram(asset) {
104
- if (!asset.program)
105
- throw new UsageError(`Workflow asset ${asset.ref} has no YAML program.`);
106
- const compiled = compileWorkflowProgram(asset.program);
121
+ function compilePlan(asset) {
122
+ const compiled = compileWorkflowPlan(asset.document, asset.title);
107
123
  if (!compiled.ok)
108
124
  throw new UsageError(compiled.errors.map((error) => `${asset.path}:${error.line}: ${error.message}`).join("\n"));
109
125
  return { ...compiled.plan, warnings: compiled.warnings };
110
126
  }
111
- function compileMarkdown(asset) {
112
- if (!asset.document)
113
- throw new UsageError(`Workflow asset ${asset.ref} has no source document.`);
114
- return { ...compileWorkflowPlan(asset.document), warnings: [] };
115
- }
116
127
  function selectedEngine(config, layers) {
117
128
  for (let index = layers.length - 1; index >= 0; index--)
118
129
  if (layers[index]?.engine !== undefined)
@@ -223,18 +234,17 @@ function addSnapshot(config, name, target) {
223
234
  };
224
235
  target[name] = snapshot;
225
236
  }
226
- function freezeGateJudge(config, engines, required) {
227
- const resolved = resolveLlmEngineUse(config, [], { optional: true });
228
- if (!resolved) {
229
- if (required)
230
- throw new ConfigError("A required workflow gate needs defaults.llmEngine at start.", "LLM_NOT_CONFIGURED");
231
- return null;
237
+ function freezeGateJudge(config, engines) {
238
+ const name = config.workflow?.judgeEngine;
239
+ if (!name) {
240
+ throw new ConfigError("This workflow declares completion criteria but no verification engine is configured. Set workflow.judgeEngine to a named LLM or agent engine.", "INVALID_CONFIG_FILE");
232
241
  }
233
- addSnapshot(config, resolved.engine, engines);
242
+ const engine = engineDefinition(config, name);
243
+ addSnapshot(config, name, engines);
234
244
  return {
235
- engine: resolved.engine,
236
- model: exactModel(config, resolved.engine, engineDefinition(config, resolved.engine), []),
237
- timeoutMs: resolved.timeoutMs,
245
+ engine: name,
246
+ model: exactModel(config, name, engine, []),
247
+ timeoutMs: effectiveTimeout(config, engine, []),
238
248
  };
239
249
  }
240
250
  function frozenConcurrency(config) {
@@ -2,23 +2,147 @@
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
- * Run-parameter validation against the frozen plan's param schemas (reviewer
6
- * #12). A program can declare `params.files: { type: array }`; supplying
7
- * `--params '{"files":"not-an-array"}'` must be rejected at start rather than
8
- * silently flowing into a unit prompt. The schemas are frozen into the plan
9
- * ({@link WorkflowPlanGraph.paramSchemas}, program path only) so validation is
10
- * a pure function of the frozen plan and the supplied params — no live-asset
11
- * re-read.
5
+ * Run-parameter validation against the frozen plan's param schemas. A workflow
6
+ * can declare `params.files: { type: array }`; supplying a non-array through
7
+ * the exact-name `--files` flag must be rejected at start rather than silently
8
+ * flowing into a unit prompt. The schemas are frozen into the plan, so
9
+ * validation is a pure function of the frozen plan and supplied params.
12
10
  *
13
11
  * Uses the same bounded {@link validateJsonSchemaSubset} the engine applies to
14
- * unit output: undeclared params are permitted (the schema map only constrains
15
- * the params it names), and a workflow with no declared schemas (every Markdown
16
- * workflow, and programs without a `params:` block) validates trivially.
12
+ * unit output. Internal callers may validate partial parameter objects; the CLI
13
+ * separately rejects flags that do not exactly name declared parameters.
17
14
  *
18
15
  * Pure module: no IO, no engine imports.
19
16
  */
20
17
  import { UsageError } from "../../core/errors.js";
21
18
  import { validateJsonSchemaSubset } from "../../core/json-schema.js";
19
+ import { PROGRAM_PARAM_NAME_PATTERN } from "../program/schema.js";
20
+ /**
21
+ * Materialize exact-name CLI parameter flags against the plan being frozen for
22
+ * the run. The CLI deliberately carries raw values to this boundary so type
23
+ * coercion cannot race or drift from the persisted plan's schemas.
24
+ */
25
+ export function materializeWorkflowParameterFlags(plan, flags) {
26
+ if (flags.length === 0)
27
+ return {};
28
+ const declared = new Set(plan.params ?? Object.keys(plan.paramSchemas ?? {}));
29
+ const grouped = new Map();
30
+ for (const flag of flags) {
31
+ if (!PROGRAM_PARAM_NAME_PATTERN.test(flag.name) || !declared.has(flag.name)) {
32
+ const available = [...declared]
33
+ .sort()
34
+ .map((name) => `--${name}`)
35
+ .join(", ");
36
+ throw new UsageError(`Unknown workflow parameter "--${flag.name}". Parameter flags must exactly match a declared workflow parameter.`, "UNKNOWN_FLAG", available ? `Declared parameters: ${available}.` : "This workflow declares no parameters.");
37
+ }
38
+ const values = grouped.get(flag.name) ?? [];
39
+ values.push(flag.value);
40
+ grouped.set(flag.name, values);
41
+ }
42
+ const entries = [];
43
+ for (const [name, values] of grouped) {
44
+ const schema = plan.paramSchemas?.[name];
45
+ entries.push([name, materializeFlagValues(name, values, schema)]);
46
+ }
47
+ const params = Object.fromEntries(entries);
48
+ const errors = validateWorkflowParams(plan, params);
49
+ if (errors.length > 0) {
50
+ throw new UsageError(`Workflow parameter flags do not satisfy the workflow's declared schemas:\n${errors.map((error) => ` - ${error}`).join("\n")}`, "INVALID_FLAG_VALUE");
51
+ }
52
+ return params;
53
+ }
54
+ function materializeFlagValues(name, values, schema) {
55
+ const types = schemaTypes(schema);
56
+ if (types.includes("array")) {
57
+ if (values.length === 1 && typeof values[0] === "string" && values[0].trim().startsWith("[")) {
58
+ const parsed = parseJsonFlag(name, values[0]);
59
+ if (!Array.isArray(parsed))
60
+ throw invalidParameter(name, "must be a JSON array");
61
+ return parsed;
62
+ }
63
+ const itemSchema = isRecord(schema?.items) ? schema.items : undefined;
64
+ return values.map((value) => coerceFlagValue(name, value, itemSchema));
65
+ }
66
+ if (values.length > 1) {
67
+ throw invalidParameter(name, "was provided more than once but is not declared as an array");
68
+ }
69
+ return coerceFlagValue(name, values[0], schema);
70
+ }
71
+ function coerceFlagValue(name, raw, schema) {
72
+ const types = schemaTypes(schema);
73
+ if (types.length === 0)
74
+ return raw;
75
+ if (typeof raw === "boolean") {
76
+ if (types.includes("boolean"))
77
+ return raw;
78
+ if (types.includes("string"))
79
+ return String(raw);
80
+ throw invalidParameter(name, `requires a value of type ${types.join(" | ")}`);
81
+ }
82
+ // A union that permits strings keeps the user's exact text. This prevents a
83
+ // value such as "001" from being silently converted to a number.
84
+ if (types.includes("string"))
85
+ return raw;
86
+ for (const type of types) {
87
+ switch (type) {
88
+ case "boolean":
89
+ if (raw === "true")
90
+ return true;
91
+ if (raw === "false")
92
+ return false;
93
+ break;
94
+ case "number": {
95
+ const value = Number(raw);
96
+ if (raw.trim() !== "" && Number.isFinite(value))
97
+ return value;
98
+ break;
99
+ }
100
+ case "integer": {
101
+ const value = Number(raw);
102
+ if (raw.trim() !== "" && Number.isSafeInteger(value))
103
+ return value;
104
+ break;
105
+ }
106
+ case "null":
107
+ if (raw === "null")
108
+ return null;
109
+ break;
110
+ case "object": {
111
+ const parsed = parseJsonFlag(name, raw);
112
+ if (isRecord(parsed))
113
+ return parsed;
114
+ break;
115
+ }
116
+ case "array": {
117
+ const parsed = parseJsonFlag(name, raw);
118
+ if (Array.isArray(parsed))
119
+ return parsed;
120
+ break;
121
+ }
122
+ }
123
+ }
124
+ throw invalidParameter(name, `must be ${types.join(" | ")}; received ${JSON.stringify(raw)}`);
125
+ }
126
+ function schemaTypes(schema) {
127
+ const declared = schema?.type;
128
+ if (typeof declared === "string")
129
+ return [declared];
130
+ return Array.isArray(declared) ? declared.filter((value) => typeof value === "string") : [];
131
+ }
132
+ function parseJsonFlag(name, raw) {
133
+ try {
134
+ return JSON.parse(raw);
135
+ }
136
+ catch {
137
+ throw invalidParameter(name, "must contain valid JSON");
138
+ }
139
+ }
140
+ function invalidParameter(name, message) {
141
+ return new UsageError(`Workflow parameter "--${name}" ${message}.`, "INVALID_FLAG_VALUE");
142
+ }
143
+ function isRecord(value) {
144
+ return typeof value === "object" && value !== null && !Array.isArray(value);
145
+ }
22
146
  /**
23
147
  * Validate a run's supplied params against the plan's frozen param schemas.
24
148
  * Returns a flat list of human-readable, path-prefixed error strings (empty =
@@ -37,7 +161,7 @@ export function validateWorkflowParams(plan, params) {
37
161
  return validateJsonSchemaSubset(params, { type: "object", properties: schemas }).map((e) => e.replace(/^\$/, "params"));
38
162
  }
39
163
  /**
40
- * Brief/report integrity assert (reviewer #12): the journaled `params_json`
164
+ * Run-integrity assert (reviewer #12): the journaled `params_json`
41
165
  * row must STILL satisfy the frozen param schemas. `startWorkflowRun` already
42
166
  * validated the params it stored, so a violation here means the row was edited
43
167
  * after the run started — loud corruption, exactly like the frozen-plan hash
@@ -4,7 +4,7 @@
4
4
  /**
5
5
  * Plan hashing for the frozen-plan contract (redesign addendum, R1).
6
6
  *
7
- * `workflow start` persists `plan_json` + `plan_hash` on the run row
7
+ * `workflow run` persists `plan_json` + `plan_hash` on the run row
8
8
  * (migration 006); every later invocation executes that snapshot. The hash is
9
9
  * the sha256 (hex) of the plan's CANONICAL JSON — object keys recursively
10
10
  * sorted — so two structurally-equal plans hash identically regardless of key
@@ -5,9 +5,9 @@ import path from "node:path";
5
5
  import { UsageError } from "../../core/errors.js";
6
6
  import { formatExtraParamsIssue, validateExtraParams } from "../../core/extra-params.js";
7
7
  import { HARNESS_BY_ID } from "../../integrations/harnesses/index.js";
8
- import { listReferences, parseTemplate } from "../program/expressions.js";
8
+ import { parseReference } from "../program/expressions.js";
9
9
  import { PROGRAM_PARAM_NAME_PATTERN, PROGRAM_RETRY_REASONS, PROGRAM_STEP_ID_PATTERN } from "../program/schema.js";
10
- import { jsonBytes, WORKFLOW_MAX_ENGINES, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_INSTRUCTION_BYTES, WORKFLOW_MAX_JSON_DEPTH, WORKFLOW_MAX_MAP_EXPANSION, WORKFLOW_MAX_PARAMS, WORKFLOW_MAX_PLAN_BYTES, WORKFLOW_MAX_ROUTE_BRANCHES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_STEPS, } from "../resource-limits.js";
10
+ import { jsonBytes, WORKFLOW_MAX_ENGINES, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_INPUTS, WORKFLOW_MAX_INSTRUCTION_BYTES, WORKFLOW_MAX_JSON_DEPTH, WORKFLOW_MAX_MAP_EXPANSION, WORKFLOW_MAX_PARAMS, WORKFLOW_MAX_PLAN_BYTES, WORKFLOW_MAX_ROUTE_BRANCHES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_STEPS, } from "../resource-limits.js";
11
11
  /** The only executable persisted workflow plan format. */
12
12
  export const WORKFLOW_IR_VERSION = 3;
13
13
  export const WORKFLOW_MAX_CONCURRENCY = 64;
@@ -110,8 +110,12 @@ export function decodeWorkflowPlanV3(input, hooks = {}) {
110
110
  assertUnitEngineCompatibility(step.root, engines);
111
111
  if (step.gate.judge) {
112
112
  const judge = engines[step.gate.judge.engine];
113
- if (!judge || judge.kind !== "llm")
114
- fail(`gate ${step.gate.id} must reference an LLM engine`);
113
+ if (!judge)
114
+ fail(`gate ${step.gate.id} references an unavailable engine`);
115
+ if (judge.kind === "llm" && step.gate.judge.model === null)
116
+ fail(`LLM gate ${step.gate.id} has no exact model`);
117
+ if (judge.kind === "agent" && step.gate.judge.llm !== undefined)
118
+ fail(`agent gate ${step.gate.id} cannot carry LLM invocation settings`);
115
119
  }
116
120
  }
117
121
  return plan;
@@ -249,6 +253,7 @@ function validateNode(node, stepId, references, nodeIds, hooks) {
249
253
  "id",
250
254
  "instructions",
251
255
  "templating",
256
+ "inputs",
252
257
  "invocation",
253
258
  "schema",
254
259
  "retry",
@@ -271,6 +276,7 @@ function validateNode(node, stepId, references, nodeIds, hooks) {
271
276
  validateSchema(node.schema, `unit ${node.id} schema`);
272
277
  validateRetry(node.retry, node.id);
273
278
  validateStringArray(node.env, `unit ${node.id} env`, MAX_LIST_ITEMS, true);
279
+ validateStringArray(node.inputs, `unit ${node.id} inputs`, WORKFLOW_MAX_INPUTS, true);
274
280
  validateSource(node.source, `unit ${node.id} source`);
275
281
  validateInvocation(node.invocation, references, hooks);
276
282
  }
@@ -284,17 +290,14 @@ function validateGate(gate, stepId, references, nodeIds, hooks) {
284
290
  !gate.criteria.every((x) => typeof x === "string" && x.length > 0 && x.length <= MAX_STRING_LENGTH) ||
285
291
  !Number.isInteger(gate.maxLoops) ||
286
292
  gate.maxLoops < 1 ||
287
- gate.maxLoops > WORKFLOW_MAX_GATE_LOOPS ||
288
- typeof gate.required !== "boolean")
293
+ gate.maxLoops > WORKFLOW_MAX_GATE_LOOPS)
289
294
  fail(`gate for step ${stepId} is invalid`);
290
295
  if (nodeIds.has(gate.id))
291
296
  fail(`gate id ${gate.id} collides with a node`);
292
- assertKeys(gate, ["kind", "id", "stepId", "criteria", "maxLoops", "required", "judge"], `gate ${stepId}`);
297
+ assertKeys(gate, ["kind", "id", "stepId", "criteria", "maxLoops", "judge"], `gate ${stepId}`);
293
298
  nodeIds.add(gate.id);
294
299
  if (gate.criteria.length === 0 && gate.judge !== null)
295
300
  fail(`gate ${gate.id} without criteria cannot have a judge`);
296
- if (gate.required && gate.criteria.length === 0)
297
- fail(`gate ${gate.id} cannot be required without criteria`);
298
301
  if (gate.judge !== null)
299
302
  validateInvocation(gate.judge, references, hooks);
300
303
  }
@@ -461,31 +464,27 @@ function validateExtraParamsValue(value, label, hooks) {
461
464
  fail(`${label}: ${policyError}`);
462
465
  }
463
466
  function validateStepExpressions(step, index, steps) {
464
- const validateReferences = (text, label, itemAllowed, wholeValue) => {
465
- const parsed = parseTemplate(text);
467
+ const validateReference = (text, label, paramsAllowed) => {
468
+ const parsed = parseReference(text);
466
469
  if (!parsed.ok)
467
- fail(`${label} contains an invalid expression`);
468
- if (wholeValue && (parsed.segments.length !== 1 || parsed.segments[0]?.kind !== "reference"))
469
- fail(`${label} must be one whole-value expression`);
470
- for (const reference of listReferences(parsed.segments)) {
471
- if ((reference.kind === "item" || reference.kind === "itemIndex") && !itemAllowed)
472
- fail(`${label} uses item outside a map unit`);
473
- if (reference.kind === "stepOutput") {
474
- const referenced = steps.get(reference.stepId);
475
- if (referenced === undefined || referenced >= index)
476
- fail(`${label} references a non-earlier step`);
477
- }
470
+ fail(`${label} contains an invalid reference`);
471
+ if (parsed.expr.kind === "param" && !paramsAllowed)
472
+ fail(`${label} must reference a step output`);
473
+ if (parsed.expr.kind === "stepOutput") {
474
+ const referenced = steps.get(parsed.expr.stepId);
475
+ if (referenced === undefined || referenced >= index)
476
+ fail(`${label} references a non-earlier step`);
478
477
  }
479
478
  };
480
479
  if (step.root) {
481
480
  const unit = step.root.kind === "map" ? step.root.template : step.root;
482
481
  if (step.root.kind === "map")
483
- validateReferences(step.root.over, `map ${step.root.id} over`, false, true);
484
- if (unit.templating === "expressions")
485
- validateReferences(unit.instructions, `unit ${unit.id} instructions`, step.root.kind === "map", false);
482
+ validateReference(step.root.over, `map ${step.root.id} over`, true);
483
+ for (const reference of unit.inputs ?? [])
484
+ validateReference(reference, `unit ${unit.id} inputs`, false);
486
485
  }
487
486
  if (step.route)
488
- validateReferences(step.route.input, `route ${step.stepId} input`, false, true);
487
+ validateReference(step.route.input, `route ${step.stepId} input`, true);
489
488
  }
490
489
  function validateSource(value, label) {
491
490
  if (value === undefined)