akm-cli 0.9.31 → 0.10.261002-beta

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 (270) hide show
  1. package/CHANGELOG.md +420 -0
  2. package/STABILITY.md +99 -57
  3. package/dist/api-node.mjs +20 -0
  4. package/dist/api.d.ts +23 -0
  5. package/dist/api.js +45 -0
  6. package/dist/assets/hints/cli-hints-full.md +15 -29
  7. package/dist/assets/hints/cli-hints-short.md +2 -2
  8. package/dist/assets/improve-strategies/default.json +3 -3
  9. package/dist/assets/prompts/consolidate-pair.md +9 -7
  10. package/dist/assets/stash-skeleton/README.md +1 -1
  11. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  12. package/dist/cli/shared.js +31 -48
  13. package/dist/cli/unknown-flags.js +6 -43
  14. package/dist/cli.js +8 -34
  15. package/dist/commands/agent/contribute-cli.js +1 -1
  16. package/dist/commands/completions.js +1 -2
  17. package/dist/commands/config-cli.js +5 -28
  18. package/dist/commands/env/env-cli.js +5 -5
  19. package/dist/commands/env/secret-cli.js +2 -2
  20. package/dist/commands/feedback-cli.js +75 -49
  21. package/dist/commands/health/checks.js +41 -16
  22. package/dist/commands/health/plugin-staleness.js +52 -22
  23. package/dist/commands/improve/autonomy-gate.js +5 -3
  24. package/dist/commands/improve/consolidate/chunking.js +3 -10
  25. package/dist/commands/improve/consolidate/continuity-check.js +4 -4
  26. package/dist/commands/improve/consolidate/pair-pass.js +29 -10
  27. package/dist/commands/improve/consolidate.js +10 -65
  28. package/dist/commands/improve/distill/lesson-update.js +91 -0
  29. package/dist/commands/improve/distill-guards.js +1 -43
  30. package/dist/commands/improve/distill.js +148 -21
  31. package/dist/commands/improve/eligibility.js +14 -1
  32. package/dist/commands/improve/extract-cli.js +1 -1
  33. package/dist/commands/improve/extract-prompt.js +17 -7
  34. package/dist/commands/improve/extract.js +5 -7
  35. package/dist/commands/improve/improve-cli.js +92 -106
  36. package/dist/commands/improve/improve-strategies.js +8 -12
  37. package/dist/commands/improve/improve.js +134 -52
  38. package/dist/commands/improve/loop-stages.js +18 -5
  39. package/dist/commands/improve/planner.js +0 -1
  40. package/dist/commands/improve/preparation.js +40 -99
  41. package/dist/commands/improve/proactive-maintenance.js +2 -2
  42. package/dist/commands/improve/reflect-noise.js +3 -55
  43. package/dist/commands/improve/reflect.js +29 -34
  44. package/dist/commands/improve/retrieval-queries.js +37 -0
  45. package/dist/commands/improve/retrieval-scope.js +2 -2
  46. package/dist/commands/improve/salience.js +2 -9
  47. package/dist/commands/improve/session-asset.js +4 -1
  48. package/dist/commands/improve/stage.js +23 -12
  49. package/dist/commands/lint/index.js +5 -20
  50. package/dist/commands/observability-cli.js +3 -9
  51. package/dist/commands/proposal/drain.js +43 -6
  52. package/dist/commands/proposal/proposal-cli.js +11 -31
  53. package/dist/commands/proposal/repository.js +20 -14
  54. package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
  55. package/dist/commands/read/knowledge.js +3 -3
  56. package/dist/commands/read/remember-cli.js +0 -13
  57. package/dist/commands/read/search-cli.js +29 -97
  58. package/dist/commands/read/search.js +0 -11
  59. package/dist/commands/read/show.js +0 -19
  60. package/dist/commands/sources/plugin-upgrade.js +164 -101
  61. package/dist/commands/sources/sources-cli.js +1 -15
  62. package/dist/commands/sources/stash-cli.js +6 -14
  63. package/dist/commands/tasks/tasks-cli.js +4 -115
  64. package/dist/commands/workflow/plan.js +11 -33
  65. package/dist/commands/workflow-cli.js +2 -7
  66. package/dist/core/adapter/adapter-ids.js +1 -2
  67. package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
  68. package/dist/core/adapter/adapters/akm-adapter.js +9 -48
  69. package/dist/core/adapter/adapters/akm-lint.js +10 -26
  70. package/dist/core/adapter/adapters/akm-metadata.js +2 -72
  71. package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
  72. package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
  73. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
  74. package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
  75. package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
  76. package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
  77. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
  78. package/dist/core/adapter/recognize-match.js +3 -4
  79. package/dist/core/common.js +18 -2
  80. package/dist/core/config/config-schema.js +12 -15
  81. package/dist/core/config/config-types.js +6 -15
  82. package/dist/core/config/config-walker.js +6 -23
  83. package/dist/core/config/config.js +17 -80
  84. package/dist/core/config/engine-semantics.js +7 -3
  85. package/dist/core/config/schema/engines.js +7 -7
  86. package/dist/core/config/schema/improve-processes.js +10 -63
  87. package/dist/core/config/schema/improve.js +2 -21
  88. package/dist/core/config/schema/index-config.js +6 -39
  89. package/dist/core/env-secret-ref.js +2 -45
  90. package/dist/core/errors.js +1 -2
  91. package/dist/core/extra-params.js +2 -86
  92. package/dist/core/file-lock.js +2 -6
  93. package/dist/core/improve-result.js +13 -1
  94. package/dist/core/mutation-target.js +2 -2
  95. package/dist/core/paths.js +4 -0
  96. package/dist/core/recognition-util.js +4 -5
  97. package/dist/core/run-lock.js +1 -1
  98. package/dist/core/subprocess.js +49 -0
  99. package/dist/core/warn.js +21 -4
  100. package/dist/core/write-source.js +3 -3
  101. package/dist/execution/target-ref.js +1 -2
  102. package/dist/indexer/indexer.js +15 -6
  103. package/dist/indexer/passes/memory-inference.js +15 -6
  104. package/dist/indexer/search/db-search.js +49 -36
  105. package/dist/indexer/search/fts-query.js +0 -19
  106. package/dist/indexer/search/ranking.js +29 -1
  107. package/dist/indexer/usage/usage-events.js +21 -16
  108. package/dist/integrations/agent/engine-resolution.js +5 -2
  109. package/dist/integrations/agent/index.js +1 -1
  110. package/dist/integrations/agent/profiles.js +41 -98
  111. package/dist/integrations/agent/request-lowering.js +3 -3
  112. package/dist/integrations/harnesses/aider/index.js +5 -0
  113. package/dist/integrations/harnesses/amazonq/index.js +1 -0
  114. package/dist/integrations/harnesses/claude/config-import.js +2 -3
  115. package/dist/integrations/harnesses/claude/index.js +5 -0
  116. package/dist/integrations/harnesses/codex/index.js +1 -0
  117. package/dist/integrations/harnesses/copilot/index.js +1 -0
  118. package/dist/integrations/harnesses/gemini/index.js +1 -0
  119. package/dist/integrations/harnesses/index.js +18 -39
  120. package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
  121. package/dist/integrations/harnesses/opencode/config-import.js +121 -52
  122. package/dist/integrations/harnesses/opencode/index.js +22 -0
  123. package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
  124. package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
  125. package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
  126. package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
  127. package/dist/integrations/harnesses/opencode/session-log.js +104 -115
  128. package/dist/integrations/harnesses/opencode/version.js +98 -0
  129. package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
  130. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
  131. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
  132. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
  133. package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
  134. package/dist/integrations/harnesses/openhands/index.js +1 -0
  135. package/dist/integrations/harnesses/pi/index.js +1 -0
  136. package/dist/integrations/harnesses/shared.js +2 -0
  137. package/dist/integrations/harnesses/types.js +2 -0
  138. package/dist/llm/client.js +41 -11
  139. package/dist/output/cli-hints.js +1 -1
  140. package/dist/output/context.js +10 -19
  141. package/dist/output/format-exempt.js +5 -8
  142. package/dist/output/shapes/helpers.js +1 -22
  143. package/dist/output/shapes/passthrough.js +0 -1
  144. package/dist/output/shapes.js +3 -31
  145. package/dist/output/stdout.js +5 -1
  146. package/dist/output/text/command-format.js +6 -1
  147. package/dist/output/text/workflow-format.js +4 -22
  148. package/dist/scripts/akm-migrate-node.js +15745 -16711
  149. package/dist/scripts/akm-migrate.js +16318 -17280
  150. package/dist/setup/detect.js +10 -4
  151. package/dist/setup/harness-config-import.js +5 -14
  152. package/dist/setup/setup.js +1 -1
  153. package/dist/setup/steps/tasks.js +12 -13
  154. package/dist/sources/providers/git-stash.js +113 -16
  155. package/dist/storage/repositories/index-utility-repository.js +2 -32
  156. package/dist/storage/repositories/index-vec-repository.js +4 -0
  157. package/dist/storage/repositories/task-history-repository.js +0 -5
  158. package/dist/storage/repositories/workflow-runs-repository.js +5 -15
  159. package/dist/tasks/embedded.js +2 -1
  160. package/dist/tasks/run/run-command-task.js +9 -1
  161. package/dist/tasks/run/run-workflow-task.js +4 -3
  162. package/dist/tasks/run/task-history.js +0 -2
  163. package/dist/tasks/run/task-log.js +38 -1
  164. package/dist/tasks/schedule-gates.js +39 -0
  165. package/dist/tasks/scheduler-binding.js +0 -16
  166. package/dist/tasks/scheduler-sync.js +3 -97
  167. package/dist/tasks/source/bounded-document.js +1 -1
  168. package/dist/tasks/source/task-source-v4.js +2 -12
  169. package/dist/tasks/task-run-reserved-flags.js +2 -31
  170. package/dist/workflows/authoring/authoring.js +6 -6
  171. package/dist/workflows/compile.js +8 -65
  172. package/dist/workflows/exec/child-workflow.js +22 -3
  173. package/dist/workflows/exec/native-executor.js +12 -147
  174. package/dist/workflows/exec/run-workflow.js +31 -103
  175. package/dist/workflows/exec/step-work.js +9 -178
  176. package/dist/workflows/exec/unit-dispatch.js +0 -10
  177. package/dist/workflows/freeze/environment.js +3 -44
  178. package/dist/workflows/freeze/freeze.js +8 -41
  179. package/dist/workflows/freeze/targets/child-workflow.js +27 -63
  180. package/dist/workflows/freeze/targets/command.js +2 -16
  181. package/dist/workflows/freeze/targets/shell.js +0 -2
  182. package/dist/workflows/freeze/task-bindings.js +2 -28
  183. package/dist/workflows/ir/params.js +12 -2
  184. package/dist/workflows/parser.js +82 -232
  185. package/dist/workflows/plan.js +1 -1
  186. package/dist/workflows/renderer.js +10 -19
  187. package/dist/workflows/runtime/run-plan.js +11 -53
  188. package/dist/workflows/runtime/runs.js +4 -27
  189. package/dist/workflows/source-files.js +12 -16
  190. package/dist/workflows/source-semantics.js +1 -93
  191. package/docs/README.md +1 -1
  192. package/docs/agents/README.md +3 -3
  193. package/docs/agents/agent-install.md +1 -1
  194. package/docs/architecture/0.10-process-rules.md +827 -0
  195. package/docs/architecture/adapters.md +17 -31
  196. package/docs/architecture/architecture.md +4 -5
  197. package/docs/architecture/improvement.md +115 -76
  198. package/docs/architecture/internals/improve-workflow.md +22 -16
  199. package/docs/architecture/internals/indexing.md +1 -1
  200. package/docs/architecture/internals/search.md +1 -2
  201. package/docs/architecture/internals/storage-locations.md +6 -6
  202. package/docs/architecture/persisted-data-compat.md +13 -4
  203. package/docs/architecture/specs/0.9.0-decisions.md +6 -2
  204. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
  205. package/docs/architecture/specs/workflow-format-unification.md +1 -6
  206. package/docs/architecture/testing/manual-testing-checklist.md +21 -30
  207. package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
  208. package/docs/architecture/testing/testing-workflow.md +1 -1
  209. package/docs/architecture/workflow-engine.md +5 -56
  210. package/docs/guides/author-workflows.md +39 -69
  211. package/docs/guides/bundles.md +3 -1
  212. package/docs/guides/capture-knowledge.md +1 -1
  213. package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
  214. package/docs/guides/discover-and-load.md +4 -4
  215. package/docs/guides/getting-started.md +1 -1
  216. package/docs/guides/improve-the-library.md +10 -9
  217. package/docs/guides/recipes/headless-install.md +2 -2
  218. package/docs/guides/run-workflows.md +1 -1
  219. package/docs/guides/scheduling.md +9 -1
  220. package/docs/guides/use-with-any-agent.md +49 -4
  221. package/docs/integration/bundling-akm.md +7 -6
  222. package/docs/maintainers/curate-workmap.md +1 -2
  223. package/docs/maintainers/release-checklist.md +33 -1
  224. package/docs/migration/README.md +2 -0
  225. package/docs/migration/release-notes/0.10.0.md +201 -0
  226. package/docs/migration/release-notes/README.md +1 -0
  227. package/docs/migration/v0.9-to-v0.10.md +507 -0
  228. package/docs/posts/akm-command-tour.md +3 -3
  229. package/docs/product-surface.md +1 -1
  230. package/docs/reference/README.md +1 -0
  231. package/docs/reference/api.md +65 -0
  232. package/docs/reference/asset-types.md +3 -5
  233. package/docs/reference/bundle-types.md +2 -4
  234. package/docs/reference/cli.md +160 -188
  235. package/docs/reference/configuration.md +101 -20
  236. package/docs/reference/data-and-telemetry.md +2 -2
  237. package/docs/reference/env-and-secrets.md +2 -2
  238. package/docs/reference/supported-formats.md +3 -4
  239. package/docs/reference/tasks.md +12 -19
  240. package/docs/reference/website-sources.md +1 -1
  241. package/docs/reference/workflow-schema.md +89 -317
  242. package/docs/reference/workflows.md +20 -48
  243. package/package.json +12 -2
  244. package/schemas/akm-config.json +2 -243
  245. package/schemas/akm-task.json +2 -3
  246. package/schemas/akm-workflow.json +47 -84
  247. package/dist/assets/improve-strategies/catchup.json +0 -41
  248. package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
  249. package/dist/assets/improve-strategies/quick.json +0 -17
  250. package/dist/assets/improve-strategies/reflect-distill.json +0 -29
  251. package/dist/assets/improve-strategies/thorough.json +0 -49
  252. package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
  253. package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
  254. package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
  255. package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
  256. package/dist/cli/retired-commands.js +0 -118
  257. package/dist/commands/improve/retrieval-gate.js +0 -132
  258. package/dist/commands/tasks/validate.js +0 -176
  259. package/dist/core/config/legacy-source-shape-shim.js +0 -117
  260. package/dist/indexer/feedback/utility-policy.js +0 -75
  261. package/dist/integrations/harnesses/ids.js +0 -28
  262. package/dist/tasks/source/task-source-v3-frozen.js +0 -424
  263. package/dist/tasks/source/task-to-v4.js +0 -863
  264. package/dist/workflows/exec/worktree.js +0 -372
  265. package/dist/workflows/freeze/child-output-references.js +0 -83
  266. package/dist/workflows/freeze/identity.js +0 -22
  267. package/dist/workflows/freeze/targets/script.js +0 -50
  268. package/dist/workflows/freeze/targets/task.js +0 -124
  269. package/dist/workflows/github-yaml.js +0 -506
  270. package/dist/workflows/runtime/run-outputs.js +0 -80
@@ -3,7 +3,6 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { captureFrozenDirectoryIdentity } from "../../../execution/directory-identity.js";
5
5
  import { freezeEnvironment } from "../environment.js";
6
- import { gitIdentity } from "../identity.js";
7
6
  import { freezeExecSpec, } from "../step-values.js";
8
7
  export function directShell(source, baseUnit, context) {
9
8
  const authoredExec = baseUnit.exec;
@@ -17,7 +16,6 @@ export function directShell(source, baseUnit, context) {
17
16
  contentHash: "",
18
17
  exec,
19
18
  cwdIdentity,
20
- ...gitIdentity(baseUnit, cwdIdentity.realRoot),
21
19
  });
22
20
  return {
23
21
  target,
@@ -4,10 +4,8 @@
4
4
  /**
5
5
  * Pure freeze-time binding of a composing step's inputs.
6
6
  * {@link freezeTaskInputBindings} classifies an authored `with:` against a
7
- * contract; {@link rebindTaskInputBindings} re-binds already-classified
8
- * bindings by name against another contract (a task's effective inputs
9
- * against a child workflow's `params:`) without re-deriving their kind. A
10
- * reference's resolved value is validated before each attempt (`exec/step-work.ts`).
7
+ * child workflow's `params:` contract. A reference's resolved value is
8
+ * validated before each attempt (`exec/step-work.ts`).
11
9
  * See docs/architecture/decisions/0008-task-binding-normalization.md.
12
10
  */
13
11
  import { isRecord } from "../../core/common.js";
@@ -41,30 +39,6 @@ export function freezeTaskInputBindings(input) {
41
39
  }
42
40
  return finalizeBindings(stepId, targetRef, contract, byName);
43
41
  }
44
- /**
45
- * Re-bind already-normalized bindings by name against a different contract,
46
- * keeping each entry's kind (a literal shaped like `{from}` stays a literal).
47
- * A literal is validated against the new contract; a reference keeps its
48
- * `from` and takes the new contract's schema; undeclared names are
49
- * `INPUT_BINDING_INVALID`; missing keys are defaulted or required as usual.
50
- */
51
- export function rebindTaskInputBindings(input) {
52
- const { stepId, targetRef, contract } = input;
53
- const declaredNames = Object.keys(contract).sort();
54
- const byName = new Map();
55
- for (const binding of input.bindings ?? []) {
56
- if (!Object.hasOwn(contract, binding.name)) {
57
- throw unknownBindingNameError(stepId, targetRef, binding.name, declaredNames);
58
- }
59
- const declaration = contract[binding.name];
60
- if (!declaration)
61
- throw inputBindingInvalid(`Workflow step ${stepId} targets ${targetRef} with.${binding.name} is invalid.`);
62
- byName.set(binding.name, binding.kind === "literal"
63
- ? binding
64
- : Object.freeze({ kind: "reference", name: binding.name, from: binding.from, schema: declaration.schema }));
65
- }
66
- return finalizeBindings(stepId, targetRef, contract, byName);
67
- }
68
42
  /** Shared tail: apply defaults (or require), schema-validate every literal, and sort by name. */
69
43
  function finalizeBindings(stepId, targetRef, contract, byName) {
70
44
  for (const [name, declaration] of Object.entries(contract)) {
@@ -7,13 +7,16 @@
7
7
  * every declared param is optional, and the messages are the workflow ones.
8
8
  */
9
9
  import { UsageError } from "../../core/errors.js";
10
- import { materializeInputFlags, validateInputs, } from "../../execution/input-contract.js";
10
+ import { applyInputDefaults, materializeInputFlags, validateInputs, } from "../../execution/input-contract.js";
11
11
  /** Every declared workflow param as an `InputDeclaration`, `required: false` — workflow params declare nothing required. */
12
12
  function contractFromPlan(plan) {
13
13
  const names = plan.params ?? Object.keys(plan.paramSchemas ?? {});
14
14
  const contract = {};
15
15
  for (const name of names) {
16
- contract[name] = { schema: plan.paramSchemas?.[name] ?? {}, required: false };
16
+ const schema = plan.paramSchemas?.[name] ?? {};
17
+ contract[name] = Object.hasOwn(schema, "default")
18
+ ? { schema, default: schema.default, required: false }
19
+ : { schema, required: false };
17
20
  }
18
21
  return contract;
19
22
  }
@@ -45,6 +48,13 @@ export function materializeWorkflowParameterFlags(plan, flags) {
45
48
  return {};
46
49
  return materializeInputFlags(contractFromPlan(plan), flags, WORKFLOW_PARAMETER_DIAGNOSTICS);
47
50
  }
51
+ /**
52
+ * Fill each declared param the run did not supply with its `default:`. An
53
+ * explicit value always wins; params without a default stay absent.
54
+ */
55
+ export function applyWorkflowParamDefaults(plan, params) {
56
+ return applyInputDefaults(contractFromPlan(plan), params);
57
+ }
48
58
  /**
49
59
  * Validate a run's supplied params against the plan's frozen param schemas.
50
60
  * Returns a flat list of human-readable, path-prefixed error strings (empty =
@@ -19,8 +19,8 @@
19
19
  *
20
20
  * 1. Every level-2 heading must be `## <step-id>` for a DECLARED step,
21
21
  * exactly (fenced code blocks are skipped when scanning for headings).
22
- * 2. A unit/map step MUST have a section (its instructions, byte-exact to
23
- * the next H2 or EOF); a route step MAY. Everything before the first H2
22
+ * 2. A step MUST have a section (its instructions, byte-exact to
23
+ * the next H2 or EOF). Everything before the first H2
24
24
  * is free preamble.
25
25
  * 3. Inside a step section, an optional `### gate` sub-heading starts the
26
26
  * step's gate rubric (to the section end) — the format's single
@@ -28,24 +28,24 @@
28
28
  *
29
29
  * Prose (instructions, gate rubrics, preamble) is NEVER templated or scanned
30
30
  * for reference syntax — it reaches the dispatched unit byte-exact. Only
31
- * three whole-value frontmatter positions carry the closed reference grammar
32
- * (`program/expressions.ts`): `map.over`, `route.input`, `inputs[]`.
31
+ * two whole-value frontmatter positions carry the closed reference grammar
32
+ * (`program/expressions.ts`): `map.over`, `inputs[]`.
33
33
  */
34
34
  import { LineCounter, parseDocument } from "yaml";
35
35
  import { bundleRefToString, parseBundleRef } from "../core/asset/asset-ref.js";
36
36
  import { parseFrontmatterBlock } from "../core/asset/frontmatter.js";
37
37
  import { parseMarkdownToc } from "../core/asset/markdown.js";
38
- import { compareCodePoints, isContainedRelativePath, isRecord } from "../core/common.js";
38
+ import { isContainedRelativePath, isRecord } from "../core/common.js";
39
39
  import { formatExtraParamsIssue, validateExtraParams } from "../core/extra-params.js";
40
40
  import { checkJsonSchemaDefinition, JSON_SCHEMA_SUBSET_SUPPORTED_KEYWORDS } from "../core/json-schema.js";
41
41
  import { INPUT_NAME_PATTERN } from "../execution/input-contract.js";
42
+ import { classifyTargetRef } from "../execution/target-ref.js";
42
43
  import { WORKFLOW_PLAN_VERSION, } from "./plan.js";
43
44
  import { parseReference } from "./program/expressions.js";
44
45
  import { jsonBytes, utf8Bytes, WORKFLOW_ENGINE_NAME_PATTERN, WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_CONCURRENCY, WORKFLOW_MAX_ENGINE_NAME_LENGTH, WORKFLOW_MAX_EXTRA_PARAMS_BYTES, WORKFLOW_MAX_INSTRUCTION_BYTES, WORKFLOW_MAX_SCHEMA_BYTES, WORKFLOW_MAX_SOURCE_BYTES, WORKFLOW_MAX_TIMEOUT_MS, } from "./resource-limits.js";
45
46
  // ── The Markdown grammar's vocabulary (pinned against schemas/akm-workflow.json) ──
46
47
  export const PROGRAM_REDUCERS = ["collect", "vote"];
47
48
  export const PROGRAM_ON_ERROR = ["fail", "continue"];
48
- export const PROGRAM_ISOLATION_KINDS = ["none", "worktree"];
49
49
  /** `retry.on`: exactly the persisted `AgentFailureReason` taxonomy (the `satisfies` fails typecheck on drift). */
50
50
  const RETRY_REASON_SET = {
51
51
  timeout: true,
@@ -86,22 +86,30 @@ const ENVELOPE_KEYS = [
86
86
  "status",
87
87
  "stale_after",
88
88
  ];
89
- const WORKFLOW_KEYS = ["params", "outputs", "defaults", "budget", "steps"];
89
+ const WORKFLOW_KEYS = ["params", "defaults", "budget", "steps"];
90
90
  const TOP_LEVEL_KEYS = [...ENVELOPE_KEYS, ...WORKFLOW_KEYS];
91
91
  const DEFAULTS_KEYS = ["engine", "model", "timeout", "on_error", "llm"];
92
92
  const BUDGET_KEYS = ["max_tokens", "max_units"];
93
- const STEP_KEYS = ["id", "unit", "map", "route", "inputs", "output", "gate"];
94
- const UNIT_KEYS = ["exec", "engine", "model", "llm", "timeout", "retry", "on_error", "output", "env", "isolation"];
93
+ const STEP_KEYS = ["id", "unit", "map", "inputs", "output", "gate"];
94
+ const UNIT_KEYS = [
95
+ "exec",
96
+ "workflow",
97
+ "with",
98
+ "engine",
99
+ "model",
100
+ "llm",
101
+ "timeout",
102
+ "retry",
103
+ "on_error",
104
+ "output",
105
+ "env",
106
+ ];
95
107
  const EXEC_KEYS = ["command", "cwd", "pass_env"];
96
108
  /** Unit keys that name an ENGINE dispatch and therefore cannot appear beside `exec:`. */
97
109
  const UNIT_ENGINE_KEYS = ["engine", "model", "llm"];
98
110
  const MAP_KEYS = ["over", "concurrency", "reducer", "unit"];
99
- const ROUTE_KEYS = ["input", "when", "default"];
100
111
  const RETRY_KEYS = ["max", "on"];
101
112
  const GATE_KEYS = ["max_loops"];
102
- const ROUTE_BRANCH_KEYS = ["match", "step"];
103
- /** Closed key set of one `outputs:` entry — mirrors `params:`'s bare-schema shape, plus `from`. */
104
- const OUTPUT_ENTRY_KEYS = ["from", "schema"];
105
113
  const ACTOR_STAMP_KEYS = ["by", "at"];
106
114
  const TIMEOUT_VALUE = /^(\d+)(ms|s|m)?$/;
107
115
  const TIMEOUT_HINT = `Use "<n>ms", "<n>s", "<n>m" (e.g. "10m"), or "none"`;
@@ -206,7 +214,6 @@ export function parseWorkflow(markdown, source) {
206
214
  const description = typeof root.description === "string" ? root.description : undefined;
207
215
  readTags(ctx, root.tags, frontmatterEndLine);
208
216
  const params = parseParams(ctx, root.params);
209
- const outputs = parseOutputs(ctx, root.outputs);
210
217
  const defaults = parseDefaults(ctx, root.defaults);
211
218
  const budget = parseBudget(ctx, root.budget);
212
219
  const parsedSteps = parseSteps(ctx, root.steps);
@@ -217,14 +224,12 @@ export function parseWorkflow(markdown, source) {
217
224
  const steps = parsedSteps.map((step, index) => {
218
225
  const section = sections.get(step.id);
219
226
  if (!section) {
220
- if (step.route === undefined) {
221
- errors.push({
222
- line: step.source.start,
223
- message: `Step "${step.id}" is a unit/map step and must have a "## ${step.id}" body section with its instructions.`,
224
- });
225
- }
227
+ errors.push({
228
+ line: step.source.start,
229
+ message: `Step "${step.id}" must have a "## ${step.id}" body section with its instructions.`,
230
+ });
226
231
  }
227
- else if (step.route === undefined && !section.instructions) {
232
+ else if (!section.instructions) {
228
233
  errors.push({
229
234
  line: section.headingLine,
230
235
  message: `Step "${step.id}" section ("## ${step.id}") is empty. Add the step's instructions below the heading.`,
@@ -244,15 +249,6 @@ export function parseWorkflow(markdown, source) {
244
249
  title: step.id,
245
250
  sequenceIndex: index,
246
251
  spec: stepSpec(step, section),
247
- ...(step.route
248
- ? {
249
- route: {
250
- input: step.route.input,
251
- when: Object.fromEntries(step.route.branches.map((branch) => [branch.match, branch.stepId])),
252
- ...(step.route.defaultStepId !== undefined ? { defaultStepId: step.route.defaultStepId } : {}),
253
- },
254
- }
255
- : {}),
256
252
  ...(step.output !== undefined ? { outputSchema: step.output } : {}),
257
253
  gate: {
258
254
  kind: "gate",
@@ -272,7 +268,6 @@ export function parseWorkflow(markdown, source) {
272
268
  irVersion: WORKFLOW_PLAN_VERSION,
273
269
  title: source.title ?? path.replace(/^.*[\\/]/, "").replace(/\.[^.]*$/, ""),
274
270
  ...(params && paramNames.length > 0 ? { params: paramNames, paramSchemas: params } : {}),
275
- ...(outputs ? { outputs: sortedByName(outputs) } : {}),
276
271
  ...(budget ? { budget } : {}),
277
272
  ...(defaults ? { defaults } : {}),
278
273
  ...(description ? { description } : {}),
@@ -284,14 +279,18 @@ export function parseWorkflow(markdown, source) {
284
279
  /** The authored step as the plan carries it. A prose step is inline `akm/command` literal content. */
285
280
  function stepSpec(step, section) {
286
281
  const prose = section?.instructions?.text;
287
- if (step.route)
288
- return { ...(prose?.trim() ? { instructions: prose } : {}), source: step.source };
289
282
  const dispatchUnit = step.map?.unit ?? step.unit;
290
- const { exec, source: _unitSource, ...unit } = dispatchUnit ?? { source: step.source };
283
+ const { exec, workflow, with: childWith, source: _unitSource, ...unit } = dispatchUnit ?? { source: step.source };
291
284
  return {
292
- ...(exec
293
- ? { exec: { ...exec }, ...(prose?.trim() ? { instructions: prose } : {}) }
294
- : { uses: "akm/command", commandMode: "literal", with: { content: prose ?? "" } }),
285
+ ...(workflow
286
+ ? {
287
+ workflow,
288
+ ...(childWith ? { with: childWith } : {}),
289
+ ...(prose?.trim() ? { instructions: prose } : {}),
290
+ }
291
+ : exec
292
+ ? { exec: { ...exec }, ...(prose?.trim() ? { instructions: prose } : {}) }
293
+ : { uses: "akm/command", with: { content: prose ?? "" } }),
295
294
  ...(Object.keys(unit).length > 0 ? { unit } : {}),
296
295
  ...(step.map
297
296
  ? {
@@ -306,12 +305,6 @@ function stepSpec(step, section) {
306
305
  source: step.source,
307
306
  };
308
307
  }
309
- /** `outputs:` in canonical wire order (code-point ascending by name). */
310
- function sortedByName(entries) {
311
- return Object.fromEntries(Object.keys(entries)
312
- .sort(compareCodePoints)
313
- .map((name) => [name, entries[name]]));
314
- }
315
308
  /** `xrefs` entries must be canonical asset refs. */
316
309
  function checkCanonicalXrefs(value, line, errors) {
317
310
  if (!Array.isArray(value))
@@ -521,71 +514,6 @@ function parseParams(ctx, raw) {
521
514
  }
522
515
  return Object.keys(params).length > 0 ? params : undefined;
523
516
  }
524
- /**
525
- * `outputs:`: named, optionally schema-validated projections
526
- * of step artifacts, exported when the run completes. Symmetrical with
527
- * `parseParams` above — same authoring surface, same name grammar,
528
- * same schema-subset validator, same per-schema byte bound — but each entry
529
- * is a STRUCTURED `{from, schema?}` mapping rather than a bare JSON Schema.
530
- *
531
- * `from` is validated for GRAMMAR only here: it must parse and it must be a
532
- * `steps.<id>.output(.<seg>)*` reference (never `params.<name>` — an output
533
- * projects a step artifact, never a param, B-07). Whether the named step is
534
- * actually DECLARED in this document is a semantic, cross-step check left to
535
- * `compile.ts`'s `checkWorkflowPlan`, mirroring how `inputs[]` /
536
- * `map.over` / `route.input` already split "syntax here, semantics there".
537
- */
538
- function parseOutputs(ctx, raw) {
539
- if (raw === undefined)
540
- return undefined;
541
- if (!isRecord(raw)) {
542
- ctx.err(["outputs"], `"outputs" must be a mapping of output name to { from, schema? } (e.g. report: { from: steps.summarize.output }).`);
543
- return undefined;
544
- }
545
- const outputs = {};
546
- for (const [outputName, value] of Object.entries(raw)) {
547
- const path = ["outputs", outputName];
548
- if (!PROGRAM_PARAM_NAME_PATTERN.test(outputName)) {
549
- ctx.err(path, `Output name "${outputName}" is invalid. Use letters, digits, and underscores, starting with a letter or ` +
550
- `underscore, so "steps.<child>.output.${outputName}" can address it.`);
551
- continue;
552
- }
553
- if (!isRecord(value)) {
554
- ctx.err(path, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
555
- continue;
556
- }
557
- checkUnknownKeys(ctx, value, path, OUTPUT_ENTRY_KEYS, `output "${outputName}"`);
558
- if (typeof value.from !== "string" || value.from.trim() === "") {
559
- ctx.err([...path, "from"], `Output "${outputName}" must declare "from": a steps.<id>.output(.<seg>)* reference.`);
560
- continue;
561
- }
562
- const parsedFrom = parseReference(value.from);
563
- if (!parsedFrom.ok) {
564
- ctx.err([...path, "from"], `Output "${outputName}" "from": ${parsedFrom.message}`);
565
- continue;
566
- }
567
- if (parsedFrom.expr.kind !== "stepOutput") {
568
- ctx.err([...path, "from"], `Output "${outputName}" "from" must reference a step output (steps.<id>.output...), not a param — an ` +
569
- `output projects a step artifact, never a param (got "${value.from}").`);
570
- continue;
571
- }
572
- const entry = { from: value.from };
573
- if (value.schema !== undefined) {
574
- if (!isRecord(value.schema)) {
575
- ctx.err([...path, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
576
- }
577
- else {
578
- if (jsonBytes(value.schema) > WORKFLOW_MAX_SCHEMA_BYTES) {
579
- ctx.err([...path, "schema"], `Output "${outputName}" schema exceeds the 256 KiB resource limit.`);
580
- }
581
- checkSchemaDefinition(ctx, value.schema, [...path, "schema"], `Output "${outputName}" schema`);
582
- entry.schema = value.schema;
583
- }
584
- }
585
- outputs[outputName] = entry;
586
- }
587
- return Object.keys(outputs).length > 0 ? outputs : undefined;
588
- }
589
517
  function parseDefaults(ctx, raw) {
590
518
  if (raw === undefined)
591
519
  return undefined;
@@ -651,17 +579,8 @@ function parseSteps(ctx, raw) {
651
579
  ctx.err(["steps"], `"steps" is required and must be a list with at least one step.`);
652
580
  return [];
653
581
  }
654
- // First pass: collect ids so route targets can be checked against ALL steps
655
- // (including ones that fail their own validation).
656
- const idIndex = new Map();
657
- raw.forEach((rawStep, index) => {
658
- if (isRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
659
- idIndex.set(rawStep.id, index);
660
- }
661
- });
662
582
  const steps = [];
663
583
  const seenIds = new Map();
664
- const routeChecks = [];
665
584
  raw.forEach((rawStep, index) => {
666
585
  const path = ["steps", index];
667
586
  if (!isRecord(rawStep)) {
@@ -689,27 +608,13 @@ function parseSteps(ctx, raw) {
689
608
  seenIds.set(id, index);
690
609
  }
691
610
  }
692
- const declaredKinds = ["map", "route"].filter((kind) => rawStep[kind] !== undefined);
693
- if (declaredKinds.length > 1) {
694
- ctx.err(path, `${label} must declare at most one of "map" or "route" (found ${declaredKinds.join(" + ")}).`);
695
- }
696
- const isRoute = rawStep.route !== undefined;
697
611
  const isMapStep = rawStep.map !== undefined;
698
- if (isRoute && rawStep.unit !== undefined) {
699
- ctx.err(path, `${label} is a route step and cannot also declare "unit" (route steps dispatch no unit).`);
700
- }
701
612
  if (isMapStep && rawStep.unit !== undefined) {
702
613
  ctx.err(path, `${label} is a map step; the per-item dispatch-override bag belongs at "map.unit", not top-level "unit".`);
703
614
  }
704
- if (isRoute && rawStep.inputs !== undefined) {
705
- ctx.err(path, `${label} is a route step and cannot declare "inputs" (route steps dispatch no unit).`);
706
- }
707
- const unit = rawStep.unit !== undefined && !isRoute && !isMapStep
708
- ? parseUnit(ctx, rawStep.unit, [...path, "unit"], label)
709
- : undefined;
615
+ const unit = rawStep.unit !== undefined && !isMapStep ? parseUnit(ctx, rawStep.unit, [...path, "unit"], label) : undefined;
710
616
  const map = isMapStep ? parseMap(ctx, rawStep.map, [...path, "map"], label) : undefined;
711
- const route = isRoute ? parseRoute(ctx, rawStep.route, [...path, "route"], label, index, routeChecks) : undefined;
712
- const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...path, "inputs"], label) : undefined;
617
+ const inputs = parseInputs(ctx, rawStep.inputs, [...path, "inputs"], label);
713
618
  const output = parseSchemaObject(ctx, rawStep.output, [...path, "output"], `${label} "output"`);
714
619
  const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...path, "gate"], label) : undefined;
715
620
  const step = { id, source: ctx.refAt(path) };
@@ -717,8 +622,6 @@ function parseSteps(ctx, raw) {
717
622
  step.unit = unit;
718
623
  if (map)
719
624
  step.map = map;
720
- if (route)
721
- step.route = route;
722
625
  if (inputs)
723
626
  step.inputs = inputs;
724
627
  if (output !== undefined)
@@ -727,31 +630,12 @@ function parseSteps(ctx, raw) {
727
630
  step.gate = gate;
728
631
  steps.push(step);
729
632
  });
730
- // Route target post-pass: targets exist, come after the routing step, and
731
- // never point back at it.
732
- for (const check of routeChecks) {
733
- const targets = [...check.branches.map((b) => ({ stepId: b.stepId, line: b.line }))];
734
- if (check.defaultTarget)
735
- targets.push(check.defaultTarget);
736
- for (const target of targets) {
737
- const targetIndex = idIndex.get(target.stepId);
738
- if (targetIndex === undefined) {
739
- ctx.errAtLine(target.line, `${check.stepLabel} routes to unknown step "${target.stepId}". Route targets must name a step id in this workflow.`);
740
- }
741
- else if (targetIndex === check.stepIndex) {
742
- ctx.errAtLine(target.line, `${check.stepLabel} must not route to itself.`);
743
- }
744
- else if (targetIndex < check.stepIndex) {
745
- ctx.errAtLine(target.line, `${check.stepLabel} routes backward to "${target.stepId}" (step ${targetIndex + 1}). Route targets must come after the routing step.`);
746
- }
747
- }
748
- }
749
633
  return steps;
750
634
  }
751
635
  // ---------------------------------------------------------------------------
752
636
  // Step blocks
753
637
  // ---------------------------------------------------------------------------
754
- function parseUnit(ctx, raw, path, stepLabel) {
638
+ function parseUnit(ctx, raw, path, stepLabel, allowWorkflow = true) {
755
639
  if (!isRecord(raw)) {
756
640
  ctx.err(path, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
757
641
  return undefined;
@@ -772,6 +656,32 @@ function parseUnit(ctx, raw, path, stepLabel) {
772
656
  `reaches an engine, so "${key}" would have no effect — remove one of the two.`);
773
657
  }
774
658
  }
659
+ if (raw.workflow !== undefined) {
660
+ const workflow = parseChildWorkflowRef(ctx, raw.workflow, [...path, "workflow"], stepLabel, allowWorkflow);
661
+ if (workflow !== undefined)
662
+ unit.workflow = workflow;
663
+ if (raw.exec !== undefined) {
664
+ ctx.err([...path, "workflow"], `${stepLabel} "unit" declares both "exec" and "workflow" — a unit runs one or the other.`);
665
+ }
666
+ // A workflow unit starts a child run: it reaches no engine and the child carries its own environment.
667
+ for (const key of [...UNIT_ENGINE_KEYS, "env"]) {
668
+ if (raw[key] === undefined)
669
+ continue;
670
+ ctx.err([...path, key], `${stepLabel} "unit" declares both "workflow" and "${key}". A workflow unit starts a child run and never ` +
671
+ `reaches an engine or an environment of its own, so "${key}" would have no effect — set it in the child workflow.`);
672
+ }
673
+ }
674
+ if (raw.with !== undefined) {
675
+ if (raw.workflow === undefined) {
676
+ ctx.err([...path, "with"], `${stepLabel} "unit" declares "with" without "workflow" — it binds a child workflow's params.`);
677
+ }
678
+ else if (!isRecord(raw.with)) {
679
+ ctx.err([...path, "with"], `${stepLabel} "with" must be a mapping of the child's param name to a literal value or { from: <reference> }.`);
680
+ }
681
+ else {
682
+ unit.with = raw.with;
683
+ }
684
+ }
775
685
  if (raw.engine !== undefined) {
776
686
  const engine = parseEngineName(ctx, raw.engine, [...path, "engine"], `${stepLabel} "engine"`);
777
687
  if (engine !== undefined)
@@ -815,11 +725,24 @@ function parseUnit(ctx, raw, path, stepLabel) {
815
725
  ctx.err([...path, "env"], `${stepLabel} "env" must be a list of non-empty env asset refs.`);
816
726
  }
817
727
  }
818
- const isolation = parseEnumField(ctx, raw.isolation, [...path, "isolation"], `${stepLabel} "isolation"`, PROGRAM_ISOLATION_KINDS);
819
- if (isolation !== undefined)
820
- unit.isolation = isolation;
821
728
  return unit;
822
729
  }
730
+ /** `unit.workflow` (Experimental): the canonical ref of a child workflow, `workflows/<name>` or `<bundle>//workflows/<name>`. */
731
+ function parseChildWorkflowRef(ctx, raw, path, stepLabel, allowed) {
732
+ if (!allowed) {
733
+ ctx.err(path, `${stepLabel} "workflow" is not supported inside "map.unit": a child workflow runs once per step.`);
734
+ return undefined;
735
+ }
736
+ try {
737
+ if (typeof raw === "string" && classifyTargetRef(raw).kind === "workflow")
738
+ return raw;
739
+ }
740
+ catch {
741
+ // falls through to the message below
742
+ }
743
+ ctx.err(path, `${stepLabel} "workflow" must be a canonical workflow ref such as "workflows/<name>".`);
744
+ return undefined;
745
+ }
823
746
  /**
824
747
  * Parse `unit.exec` — the argv-array shell-command surface.
825
748
  *
@@ -952,7 +875,7 @@ function parseMap(ctx, raw, path, stepLabel) {
952
875
  }
953
876
  }
954
877
  const reducer = parseEnumField(ctx, raw.reducer, [...path, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
955
- const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path, "unit"], stepLabel) : undefined;
878
+ const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path, "unit"], stepLabel, false) : undefined;
956
879
  const map = { over };
957
880
  if (concurrency !== undefined)
958
881
  map.concurrency = concurrency;
@@ -962,79 +885,6 @@ function parseMap(ctx, raw, path, stepLabel) {
962
885
  map.unit = unit;
963
886
  return map;
964
887
  }
965
- function parseRoute(ctx, raw, path, stepLabel, stepIndex, routeChecks) {
966
- if (!isRecord(raw)) {
967
- ctx.err(path, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
968
- return undefined;
969
- }
970
- checkUnknownKeys(ctx, raw, path, ROUTE_KEYS, `${stepLabel} "route"`);
971
- let input = "";
972
- if (typeof raw.input === "string" && raw.input.trim() !== "") {
973
- input = raw.input.trim();
974
- checkReferenceSyntax(ctx, input, [...path, "input"], `${stepLabel} "route.input"`);
975
- }
976
- else {
977
- ctx.err([...path, "input"], `${stepLabel} "route" requires "input": a reference naming the value to route on.`);
978
- }
979
- const check = { stepIndex, stepLabel, branches: [] };
980
- const whenPath = [...path, "when"];
981
- if (!Array.isArray(raw.when) || raw.when.length === 0) {
982
- ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
983
- }
984
- else {
985
- const seenMatches = new Map();
986
- raw.when.forEach((branch, i) => {
987
- const branchPath = [...whenPath, i];
988
- if (!isRecord(branch)) {
989
- ctx.err(branchPath, `${stepLabel} "when[${i}]" must be a mapping: { match, step }.`);
990
- return;
991
- }
992
- checkUnknownKeys(ctx, branch, branchPath, ROUTE_BRANCH_KEYS, `${stepLabel} "when[${i}]"`);
993
- const matchLine = ctx.lineAt([...branchPath, "match"]);
994
- if (branch.match === undefined ||
995
- (typeof branch.match !== "string" && typeof branch.match !== "number" && typeof branch.match !== "boolean")) {
996
- ctx.err([...branchPath, "match"], `${stepLabel} "when[${i}].match" must be a string, number, or boolean.`);
997
- return;
998
- }
999
- const match = String(branch.match);
1000
- // The frozen-plan decoder requires every `when` key to be non-empty, so an
1001
- // empty match parsed and linted clean and then failed the run with an
1002
- // unlocated "Invalid frozen workflow plan". Reject it here, at the line.
1003
- if (match === "") {
1004
- ctx.errAtLine(matchLine, `${stepLabel} "when[${i}].match" must not be empty.`);
1005
- return;
1006
- }
1007
- if (typeof branch.step !== "string" || branch.step.trim() === "") {
1008
- ctx.err([...branchPath, "step"], `${stepLabel} "when[${i}].step" must be a step id string.`);
1009
- return;
1010
- }
1011
- const stepId = branch.step.trim();
1012
- const stepLine = ctx.lineAt([...branchPath, "step"]);
1013
- const firstLine = seenMatches.get(match);
1014
- if (firstLine !== undefined) {
1015
- ctx.errAtLine(matchLine, `${stepLabel} has a duplicate "when" match "${match}" (first declared on line ${firstLine}). Matches must be unique.`);
1016
- return;
1017
- }
1018
- seenMatches.set(match, matchLine);
1019
- check.branches.push({ match, stepId, line: stepLine });
1020
- });
1021
- }
1022
- let defaultStepId;
1023
- if (raw.default !== undefined) {
1024
- if (typeof raw.default === "string" && raw.default.trim() !== "") {
1025
- defaultStepId = raw.default.trim();
1026
- check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...path, "default"]) };
1027
- }
1028
- else {
1029
- ctx.err([...path, "default"], `${stepLabel} "route.default" must be a step id string.`);
1030
- }
1031
- }
1032
- routeChecks.push(check);
1033
- const route = { input, branches: check.branches.map(({ match, stepId }) => ({ match, stepId })) };
1034
- if (defaultStepId !== undefined)
1035
- route.defaultStepId = defaultStepId;
1036
- return route;
1037
- }
1038
888
  function parseInputs(ctx, raw, path, stepLabel) {
1039
889
  if (raw === undefined)
1040
890
  return undefined;
@@ -1,5 +1,5 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
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
- /** Stored plans record this; earlier releases wrote 4 and 5, which still decode. */
4
+ /** Stored plans record this; 0.9.15 and 0.9.16 wrote 5, which still decodes (the 0.9.15 floor, #1091). */
5
5
  export const WORKFLOW_PLAN_VERSION = 6;
@@ -2,15 +2,15 @@
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
- * Show renderer for peer workflow sources. `.md` and `.yml` both compile
6
- * through `compileWorkflowSource` into a plan, which is projected down to the
7
- * public `ShowResponse` shape, including a compact per-step orchestration
8
- * summary (engine/model or an exec unit's argv, `map.over` reference, route
9
- * table) when the step declares one.
5
+ * Show renderer for workflow sources. A `.md` source compiles through
6
+ * `compileWorkflowSource` into a plan, which is projected down to the public
7
+ * `ShowResponse` shape, including a compact per-step orchestration summary
8
+ * (engine/model or an exec unit's argv, `map.over` reference) when the step
9
+ * declares one.
10
10
  */
11
11
  import { displayRef } from "../core/asset/resolve-ref.js";
12
12
  import { UsageError } from "../core/errors.js";
13
- import { compileWorkflowSource, routeDescription, workflowStepInstructions } from "./compile.js";
13
+ import { compileWorkflowSource, workflowStepInstructions } from "./compile.js";
14
14
  function shellQuote(value) {
15
15
  return `'${value.replace(/'/g, `'\\''`)}'`;
16
16
  }
@@ -45,7 +45,7 @@ function projectParameters(plan) {
45
45
  * Compact, show-facing orchestration summary for one step. Field mapping:
46
46
  * `engine`/`model`/`timeoutMs` merge the run-level `defaults` exactly like the
47
47
  * compiler does (per-unit override wins), `fanOut.over` carries the raw
48
- * reference string, and `route` carries the explicit input + branch table.
48
+ * reference string.
49
49
  * Returns undefined when the step declares nothing worth summarizing.
50
50
  *
51
51
  * ## exec units
@@ -54,8 +54,8 @@ function projectParameters(plan) {
54
54
  * `engine`/`model`/`llm` alongside `exec:`. Merging `defaults.engine` into its
55
55
  * summary would make `show` state something untrue about what will run, so the
56
56
  * two fields are suppressed and the argv is projected instead, under `exec`
57
- * (field presence carries the dispatch kind, exactly like `fanOut`/`route`
58
- * carry the step kind).
57
+ * (field presence carries the dispatch kind, exactly like `fanOut`
58
+ * carries the step kind).
59
59
  *
60
60
  * `timeoutMs` still merges the defaults: an exec unit really does inherit
61
61
  * `defaults.timeout`, so that number stays true for it.
@@ -94,15 +94,6 @@ function summarizeStepOrchestration(step, defaults) {
94
94
  : {}),
95
95
  ...(unit?.output !== undefined || step.outputSchema !== undefined ? { hasSchema: true } : {}),
96
96
  ...(unit?.env !== undefined ? { env: [...unit.env] } : {}),
97
- ...(step.route
98
- ? {
99
- route: {
100
- input: step.route.input,
101
- branches: Object.entries(step.route.when).map(([match, stepId]) => ({ match, stepId })),
102
- ...(step.route.defaultStepId !== undefined ? { defaultStepId: step.route.defaultStepId } : {}),
103
- },
104
- }
105
- : {}),
106
97
  };
107
98
  return Object.keys(summary).length > 0 ? summary : undefined;
108
99
  }
@@ -113,7 +104,7 @@ function projectStepDefinitions(plan) {
113
104
  return {
114
105
  id: step.stepId,
115
106
  title: step.stepId,
116
- instructions: instructions || (step.route ? routeDescription(step.route) : ""),
107
+ instructions,
117
108
  ...(step.gate.criteria.length > 0 ? { completionCriteria: [...step.gate.criteria] } : {}),
118
109
  sequenceIndex,
119
110
  ...(orchestration ? { orchestration } : {}),