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
@@ -109,11 +109,10 @@ function resolveTaskInputBindings(bindings, stepId, scope) {
109
109
  */
110
110
  export function computeStepWorkList(plan, input) {
111
111
  const root = plan.root;
112
- // Route-only steps (YAML `route:`) carry no execution subgraph.
113
112
  if (!root) {
114
113
  return {
115
114
  ok: false,
116
- error: `Step "${plan.stepId}" has no execution subgraph (a route-only step); the native executor cannot dispatch it.`,
115
+ error: `Step "${plan.stepId}" has no execution subgraph; the native executor cannot dispatch it.`,
117
116
  };
118
117
  }
119
118
  const template = root.kind === "map" ? root.template : root;
@@ -121,7 +120,7 @@ export function computeStepWorkList(plan, input) {
121
120
  const scope = { params: input.params, stepOutputs: input.stepOutputs };
122
121
  // Instructions are ALWAYS the step's body prose, byte-exact — never
123
122
  // templated, never scanned for reference syntax (workflow-format-
124
- // unification, spec §2.3). Only `map.over` / `route.input` / `inputs[]`
123
+ // unification, spec §2.3). Only `map.over` / `inputs[]`
125
124
  // carry the closed reference grammar.
126
125
  // Resolve the step's declared `inputs:` ONCE (shared by every unit in this
127
126
  // step — map items differ, declared inputs do not): prior-step artifacts
@@ -177,7 +176,7 @@ export function computeStepWorkList(plan, input) {
177
176
  : [unitIdFor(template.id, undefined, false, true)];
178
177
  const gateLoop = input.gateLoop ?? 1;
179
178
  const target = template.frozenTarget;
180
- const frozenExec = target.kind === "shell" || target.kind === "script" ? target.exec : undefined;
179
+ const frozenExec = target.kind === "shell" ? target.exec : undefined;
181
180
  const runner = target.kind === "command" ? target.runner.kind : "exec";
182
181
  // Taken verbatim from the frozen plan, resolved once at freeze (an exec
183
182
  // unit's on its exec spec). A frozen `null` means genuinely unbounded
@@ -271,7 +270,6 @@ function buildStepWorkUnit(ctx, unitId, item, index) {
271
270
  ...(template.schema ? { schema: template.schema } : {}),
272
271
  ...(template.retry ? { retry: template.retry } : {}),
273
272
  onError: template.onError,
274
- ...(template.isolation ? { isolation: template.isolation } : {}),
275
273
  // the SAME resolved `with:` bindings `taskInputs` already
276
274
  // carries, exposed under the name `child-workflow.ts`'s drive contract
277
275
  // reads. Absent (never `{}`) when the step binds nothing.
@@ -330,7 +328,8 @@ function computeUnitInputHash(ctx, item) {
330
328
  frozenTarget: ctx.target,
331
329
  environment: ctx.template.environment,
332
330
  schema: ctx.template.schema ?? null,
333
- isolation: ctx.template.isolation ?? "none",
331
+ // Retired `isolation: worktree` field; kept constant so in-flight runs keep their journaled input hashes.
332
+ isolation: "none",
334
333
  ...(ctx.taskInputs !== undefined ? { taskInputs: ctx.taskInputs } : {}),
335
334
  ...(ctx.input.gateFeedback ? { gateFeedback: ctx.input.gateFeedback } : {}),
336
335
  }))
@@ -422,7 +421,7 @@ function stepTemplate(stepPlan) {
422
421
  }
423
422
  /**
424
423
  * The step ids another step can still read (named by `inputs[]`, `map.over`,
425
- * or `route.input` — the whole reference surface). A step outside this set
424
+ * — the whole reference surface). A step outside this set
426
425
  * need not keep its artifact in memory once journaled. Derived from the plan alone.
427
426
  */
428
427
  export function referencedStepIds(plan) {
@@ -437,8 +436,6 @@ export function referencedStepIds(plan) {
437
436
  note(step.root.over);
438
437
  for (const reference of stepTemplate(step)?.inputs ?? [])
439
438
  note(reference);
440
- if (step.route)
441
- note(step.route.input);
442
439
  }
443
440
  return referenced;
444
441
  }
@@ -830,148 +827,6 @@ export async function journalGateEvaluationFinish(gate, errored, rejection) {
830
827
  throw new UsageError(`Gate ${unitId} was already finished; refusing a duplicate terminal write.`);
831
828
  }
832
829
  }
833
- /**
834
- * Resolve a route's input (a single whole-value reference string — `params.x` or
835
- * `steps.<id>.output…`, with no `${{ }}` delimiters) and pick the branch. No
836
- * ambient key search. Only primitive values route; the comparison is exact
837
- * string equality against the declared `when:` matches.
838
- */
839
- export function evaluateRoute(route, scope) {
840
- const resolved = resolveStepReference(route.input, scope);
841
- if (!resolved.ok) {
842
- return { ok: false, error: `route input ${route.input} failed to resolve: ${resolved.error.message}` };
843
- }
844
- const value = resolved.value;
845
- if (typeof value === "object" && value !== null) {
846
- return {
847
- ok: false,
848
- error: `route input ${route.input} resolved to a non-primitive value; branches match on strings/numbers/booleans.`,
849
- };
850
- }
851
- const valueString = typeof value === "string" ? value : String(value);
852
- // Own-property check: `when` is author-controlled, and a value such as
853
- // "constructor" must not resolve through Object.prototype.
854
- const selected = Object.hasOwn(route.when, valueString) ? route.when[valueString] : route.defaultStepId;
855
- if (!selected) {
856
- return {
857
- ok: false,
858
- error: `value "${valueString}" matched no "when:" branch and the route declares no default.`,
859
- };
860
- }
861
- return { ok: true, value: valueString, selected };
862
- }
863
- /**
864
- * Cascade a SKIPPED router: it never evaluated its route, so every declared
865
- * target (branches + default) is marked skip-on-reach unless an earlier router
866
- * already claimed it. Shared by the live skip path and the journal replay.
867
- */
868
- export function cascadeSkippedRouter(route, routerId, routeUnselected) {
869
- const targets = [...Object.values(route.when), ...(route.defaultStepId ? [route.defaultStepId] : [])];
870
- for (const target of targets) {
871
- if (!routeUnselected.has(target)) {
872
- routeUnselected.set(target, { router: routerId, selected: null });
873
- }
874
- }
875
- }
876
- /**
877
- * Record one router's decision in the skip bookkeeping: the selected target is
878
- * protected, every other declared target (branches + default) is marked
879
- * skip-on-reach unless an earlier router already claimed it. Shared by the live
880
- * evaluation path and the journal replay.
881
- */
882
- export function applyRouteDecision(route, routerId, selected, routeSelected, routeUnselected) {
883
- routeSelected.add(selected);
884
- const targets = [...Object.values(route.when), ...(route.defaultStepId ? [route.defaultStepId] : [])];
885
- for (const target of targets) {
886
- if (target !== selected && !routeUnselected.has(target)) {
887
- routeUnselected.set(target, { router: routerId, selected });
888
- }
889
- }
890
- }
891
- /**
892
- * The `stepOutputs` scope a route resolves against: every prior step's recorded
893
- * evidence plus the just-finished step's fresh evidence — each projected
894
- * through {@link projectStepOutput}. Same projection as unit templates, so the
895
- * two scopes cannot drift.
896
- */
897
- export function routeStepOutputs(evidence, currentStepId, currentEvidence) {
898
- const outputs = {};
899
- for (const [stepId, stepEvidence] of Object.entries(evidence)) {
900
- if (stepEvidence !== undefined)
901
- outputs[stepId] = projectStepOutput(stepEvidence);
902
- }
903
- outputs[currentStepId] = projectStepOutput(currentEvidence);
904
- return outputs;
905
- }
906
- /** The `selected` target journaled on a route step's evidence, if well-formed. */
907
- function journaledRouteSelection(evidence) {
908
- const route = evidence?.route;
909
- if (typeof route !== "object" || route === null || Array.isArray(route))
910
- return undefined;
911
- const selected = route.selected;
912
- return typeof selected === "string" && selected !== "" ? selected : undefined;
913
- }
914
- /** The set of steps a route may legally select: its `when` branches + default. */
915
- function routeTargets(route) {
916
- return new Set([...Object.values(route.when), ...(route.defaultStepId ? [route.defaultStepId] : [])]);
917
- }
918
- /** A journaled route decision must name a target the route declares; anything else fails loudly. */
919
- function assertRouteTargetDeclared(route, stepId, selected, runId) {
920
- const targets = routeTargets(route);
921
- if (!targets.has(selected)) {
922
- throw new UsageError(`Workflow run ${runId} has a completed route step "${stepId}" whose journaled route decision selected ` +
923
- `"${selected}", which is not a declared branch or default target of the route (valid targets: ` +
924
- `${[...targets].join(", ") || "(none)"}). The route evidence was corrupted or manually edited — refusing to ` +
925
- `apply a bogus route decision that would skip the real branch targets. Start a new run.`);
926
- }
927
- }
928
- /**
929
- * Replay journaled route decisions into the skip bookkeeping (resume path).
930
- * For every COMPLETED route step of the frozen plan, in spine order: the
931
- * journaled decision wins; else a re-derivation from the frozen plan +
932
- * journaled evidence; else fail loudly. A SKIPPED route step cascades its
933
- * targets into the skip set exactly as on the live path.
934
- */
935
- export function seedJournaledRouteDecisions(plan, state, routeSelected, routeUnselected) {
936
- const evidence = {};
937
- for (const s of state.workflow.steps)
938
- evidence[s.id] = s.evidence;
939
- for (const stepPlan of plan.steps) {
940
- if (!stepPlan.route)
941
- continue;
942
- const stepState = state.workflow.steps.find((s) => s.id === stepPlan.stepId);
943
- if (!stepState)
944
- continue;
945
- if (stepState.status === "skipped") {
946
- cascadeSkippedRouter(stepPlan.route, stepPlan.stepId, routeUnselected);
947
- continue;
948
- }
949
- if (stepState.status !== "completed")
950
- continue;
951
- let selected = journaledRouteSelection(stepState.evidence);
952
- if (selected !== undefined) {
953
- // a stored decision must name a declared target — a bogus one
954
- // (tampered/hand-edited evidence) fails loudly rather than seeding a skip
955
- // set that buries the real branches.
956
- assertRouteTargetDeclared(stepPlan.route, stepPlan.stepId, selected, state.run.id);
957
- }
958
- if (selected === undefined) {
959
- const scope = {
960
- params: state.run.params ?? {},
961
- stepOutputs: routeStepOutputs(evidence, stepPlan.stepId, stepState.evidence ?? {}),
962
- };
963
- const decision = evaluateRoute(stepPlan.route, scope);
964
- if (decision.ok)
965
- selected = decision.selected;
966
- }
967
- if (selected === undefined) {
968
- throw new UsageError(`Workflow run ${state.run.id} has a completed route step "${stepPlan.stepId}" with no journaled route ` +
969
- `decision, and the decision cannot be re-derived from the journaled evidence. Refusing to guess which ` +
970
- `branch was selected. The run journal is inconsistent; abandon this run and start a new one.`);
971
- }
972
- applyRouteDecision(stepPlan.route, stepPlan.stepId, selected, routeSelected, routeUnselected);
973
- }
974
- }
975
830
  /**
976
831
  * The blocked-step notes for a verifier-infrastructure failure (bug: judge
977
832
  * outage must not burn the gate budget). Shared by every judge-failure path —
@@ -1050,8 +905,6 @@ async function blockFinalizedStepForChildWorkflow(input, childBlocked) {
1050
905
  * Perform one completion attempt for an executed step:
1051
906
  * - a hard unit failure fails the step (a retryable artifact-schema mismatch
1052
907
  * with loops left returns `retry` without a gate row);
1053
- * - a route decision is evaluated, journaled on the evidence, and applied to
1054
- * the skip bookkeeping; an unroutable value fails the step;
1055
908
  * - the gate judges a summary built from the promoted artifact: a rejection
1056
909
  * returns `retry` (loops left) or `gate-exhausted`, a pass `advanced`;
1057
910
  * - a judge infrastructure failure is not a verdict: it blocks the step for
@@ -1093,34 +946,12 @@ export async function finalizeExecutedStep(input) {
1093
946
  return blockFinalizedStep(input, "this step declares completion criteria but no verification judge is available " +
1094
947
  "(the frozen plan resolves no judge — set workflow.judgeEngine, or restore the judge configuration)");
1095
948
  }
1096
- // Route evaluation BEFORE completion: an unroutable value is an
1097
- // authoring/config failure that must fail the step deterministically.
1098
- let summaryOverride;
1099
- if (stepPlan.route) {
1100
- const scope = {
1101
- params: input.params,
1102
- stepOutputs: routeStepOutputs(input.priorEvidence, stepId, result.evidence),
1103
- };
1104
- const decision = evaluateRoute(stepPlan.route, scope);
1105
- if (!decision.ok) {
1106
- const notes = `Step "${stepId}" route failed: ${decision.error}`;
1107
- await completeWorkflowStep({ runId, stepId, status: "failed", notes, evidence: result.evidence });
1108
- return { kind: "failed", summary: notes, routeFailure: true };
1109
- }
1110
- applyRouteDecision(stepPlan.route, stepId, decision.selected, input.routeSelected, input.routeUnselected);
1111
- // Journal the decision on the evidence: resume replays it via
1112
- // seedJournaledRouteDecisions, so the skip set survives re-invocation.
1113
- result.evidence.route = { input: stepPlan.route.input, value: decision.value, selected: decision.selected };
1114
- if (!stepPlan.root) {
1115
- summaryOverride = `Step "${stepId}" routed on ${stepPlan.route.input}: value "${decision.value}" selected step "${decision.selected}".`;
1116
- }
1117
- }
1118
949
  // Artifact-judging gate: a criteria-bearing executing step is judged on a
1119
950
  // summary BUILT FROM the promoted artifact; everything else keeps the machine
1120
- // summary (a route-only step's summary IS its decision).
951
+ // summary.
1121
952
  const summary = stepPlan.root && completionCriteria.length > 0
1122
953
  ? buildArtifactSummary(stepId, result.units, result.evidence)
1123
- : (summaryOverride ?? result.summary);
954
+ : result.summary;
1124
955
  // Journal engine-driven judge calls as unit rows. With no criteria there is
1125
956
  // no judge invocation or row; a criteria-bearing plan without a judge is a
1126
957
  // configuration error rather than a silent bypass.
@@ -1233,7 +1064,7 @@ export async function finalizeExecutedStep(input) {
1233
1064
  return blockFinalizedStep(input, judgeFailure ?? "the verification judge failed");
1234
1065
  }
1235
1066
  if (!rejection) {
1236
- return { kind: "advanced", ...(summaryOverride !== undefined ? { summaryOverride } : {}) };
1067
+ return { kind: "advanced" };
1237
1068
  }
1238
1069
  if (loopsRemaining) {
1239
1070
  return { kind: "retry", gateFeedback: { feedback: rejection.feedback, missing: rejection.missing } };
@@ -73,16 +73,6 @@ export async function dispatchWorkflowExecution(request, feedback) {
73
73
  ...(notices ? { notices } : {}),
74
74
  };
75
75
  }
76
- if (request.cwd && lowered.runner.kind === "llm") {
77
- return {
78
- ok: false,
79
- text: "",
80
- failureReason: "isolation_unsupported",
81
- error: `unit ${JSON.stringify(request.unitId)} declares isolation: worktree but resolved to the "llm" runner, ` +
82
- `which has no working directory to isolate. Use the agent or sdk runner for isolated units.`,
83
- ...(notices ? { notices } : {}),
84
- };
85
- }
86
76
  let result;
87
77
  try {
88
78
  const eventSource = forwardedDispatchEventSource(request);
@@ -12,23 +12,13 @@ import { UsageError } from "../../core/errors.js";
12
12
  import { deriveInstallations } from "../../indexer/installations.js";
13
13
  import { resolveSourceEntries } from "../../indexer/search/search-source.js";
14
14
  import { resolveAssetPath } from "../../sources/resolve.js";
15
- import { isInferredSecretName } from "../../tasks/log-redaction.js";
16
15
  import { SECRET_TOKEN_RE } from "../exec/environment.js";
17
- import { detectSecretShapedParams } from "../exec/param-secrets.js";
18
16
  /**
19
- * A step's frozen environment: literal `env:` values, `pass_env` names, then
17
+ * A step's frozen environment: `pass_env` names, then
20
18
  * one value-free descriptor per `unit.env` ref (owner, key set, secret-token
21
19
  * names). Values are read at dispatch (`exec/environment.ts`), never frozen.
22
20
  */
23
21
  export function freezeEnvironment(source, exec, context) {
24
- const literals = Object.entries(source.env ?? {}).map(([name, raw]) => {
25
- const value = String(raw);
26
- // A literal is frozen into plan_json; a credential belongs in an env ref, as for task env.
27
- if (isInferredSecretName(name) || detectSecretShapedParams({ [name]: value }).length > 0) {
28
- throw new UsageError(`Workflow step ${source.id} env.${name} is a secret-shaped literal env value. Store credentials in an env asset (unit.env) rather than workflow source.`, "WORKFLOW_SOURCE_INVALID");
29
- }
30
- return Object.freeze({ kind: "literal", name, value });
31
- });
32
22
  const passThrough = (exec?.passEnv ?? []).map((name) => Object.freeze({ kind: "pass-through", name }));
33
23
  const seen = new Set();
34
24
  const envRefs = [];
@@ -62,7 +52,7 @@ export function freezeEnvironment(source, exec, context) {
62
52
  precedence,
63
53
  }));
64
54
  }
65
- return [...literals, ...passThrough, ...envRefs];
55
+ return [...passThrough, ...envRefs];
66
56
  }
67
57
  /** Load a command or persona the workflow names, resolved through the workflow's own bundles. */
68
58
  export async function workflowExecutionSource(ref, kind, context) {
@@ -143,39 +133,8 @@ function configuredOwner(bundle, config) {
143
133
  adapter: component?.adapter ?? "akm",
144
134
  };
145
135
  }
146
- const SCRIPT_EXTENSIONS = [
147
- "",
148
- ".sh",
149
- ".ts",
150
- ".js",
151
- ".py",
152
- ".rb",
153
- ".go",
154
- ".pl",
155
- ".php",
156
- ".lua",
157
- ".r",
158
- ".swift",
159
- ".kt",
160
- ".kts",
161
- ".ps1",
162
- ".cmd",
163
- ".bat",
164
- ];
165
136
  function assetExtensions(type) {
166
- if (type === "script")
167
- return SCRIPT_EXTENSIONS;
168
137
  if (type === "env")
169
138
  return ["", ".env"];
170
- return ["", ".md", ".yml"];
171
- }
172
- export function qualifyRef(ref, plural, asset, config) {
173
- const parsed = parseBundleRef(ref);
174
- if (parsed.bundle)
175
- return ref;
176
- const bundle = parseBundleRef(asset.ref).bundle ?? config.defaultBundle;
177
- if (!bundle)
178
- throw new UsageError(`Workflow ref ${ref} has no owning bundle.`, "WORKFLOW_SOURCE_INVALID");
179
- const concept = parsed.conceptId.startsWith(`${plural}/`) ? parsed.conceptId : `${plural}/${parsed.conceptId}`;
180
- return makeBundleRef(bundle, concept);
139
+ return ["", ".md"];
181
140
  }
@@ -17,15 +17,10 @@ import { checkWorkflowPlan } from "../compile.js";
17
17
  import { defaultMapConcurrency, workflowMaxConcurrency } from "../concurrency-policy.js";
18
18
  import { canonicalJson } from "../ir/plan-hash.js";
19
19
  import { WORKFLOW_PLAN_VERSION, } from "../plan.js";
20
- import { classifyWorkflowStepUses } from "../source-semantics.js";
21
- import { assertChildOutputReferences } from "./child-output-references.js";
22
- import { qualifyRef } from "./environment.js";
23
20
  import { baseUnitOf } from "./step-values.js";
24
21
  import { childWorkflowDispatch } from "./targets/child-workflow.js";
25
22
  import { commandDispatch, commandResult } from "./targets/command.js";
26
- import { directScript } from "./targets/script.js";
27
23
  import { directShell } from "./targets/shell.js";
28
- import { taskDispatch } from "./targets/task.js";
29
24
  /** Resolve and freeze one workflow (and, recursively, every child it composes). */
30
25
  export async function freezeWorkflow(asset, config, refPath = [asset.ref]) {
31
26
  const compiled = asset.plan;
@@ -45,12 +40,9 @@ export async function freezeWorkflow(asset, config, refPath = [asset.ref]) {
45
40
  for (const step of compiled.steps) {
46
41
  const { spec, ...frozenStep } = step;
47
42
  const source = { ...(spec ?? { source: { path: asset.path, start: 1, end: 1 } }), id: step.stepId };
48
- let root;
49
- if (!step.route) {
50
- const resolved = await resolveStep(source, context);
51
- engineAnnouncement ??= resolved.engineAnnouncement;
52
- root = frozenRoot(step.stepId, source, resolved, compiled, config);
53
- }
43
+ const resolved = await resolveStep(source, context);
44
+ engineAnnouncement ??= resolved.engineAnnouncement;
45
+ const root = frozenRoot(step.stepId, source, resolved, compiled, config);
54
46
  let frozenJudge = null;
55
47
  if (step.gate.criteria.length > 0) {
56
48
  const judge = resolveJudge(source, step.gate.criteria[0] ?? "", context);
@@ -64,16 +56,14 @@ export async function freezeWorkflow(asset, config, refPath = [asset.ref]) {
64
56
  "for `akm workflow resume` once it is reached.");
65
57
  }
66
58
  }
67
- steps.push({ ...frozenStep, ...(root ? { root } : {}), gate: { ...step.gate, frozenJudge } });
59
+ steps.push({ ...frozenStep, root, gate: { ...step.gate, frozenJudge } });
68
60
  }
69
- assertChildOutputReferences(steps);
70
61
  const plan = {
71
62
  irVersion: WORKFLOW_PLAN_VERSION,
72
63
  title: asset.title,
73
64
  ...(compiled.params ? { params: compiled.params } : {}),
74
65
  ...(compiled.paramSchemas ? { paramSchemas: compiled.paramSchemas } : {}),
75
66
  ...(compiled.budget ? { budget: compiled.budget } : {}),
76
- ...(compiled.outputs ? { outputs: compiled.outputs } : {}),
77
67
  execution: { maxConcurrency: workflowMaxConcurrency(config.workflow?.maxConcurrency) },
78
68
  sourceHash: asset.sourceHash,
79
69
  steps,
@@ -84,33 +74,11 @@ async function resolveStep(source, context) {
84
74
  const baseUnit = baseUnitOf(source);
85
75
  if (source.exec)
86
76
  return directShell(source, baseUnit, context);
87
- if (!source.uses)
88
- throw new Error(`workflow step ${source.id} has neither exec nor uses`);
89
- const target = classifyWorkflowStepUses(source.uses);
90
- if (target.kind === "task")
91
- return taskDispatch(source, baseUnit, target.ref, context);
92
- if (target.kind === "workflow") {
93
- return childWorkflowDispatch({
94
- source,
95
- baseUnit,
96
- childRefInput: target.ref,
97
- context,
98
- via: "direct",
99
- authoredInputs: { kind: "with", value: source.with },
100
- });
101
- }
102
- // `commands/<ref>` and `scripts/<ref>` are not binding surfaces; `akm/command`'s
103
- // `with:` is its own argument bag.
104
- if (target.kind !== "builtin-command" && source.with !== undefined) {
105
- const family = target.kind === "command" ? "commands" : "scripts";
106
- throw new UsageError(`Workflow step ${source.id} cannot pass with: to ${family} target ${target.ref}; a ${target.kind} ref is not a binding surface.`, "COMPOSITION_INVALID");
77
+ if (source.workflow) {
78
+ return childWorkflowDispatch({ source, baseUnit, childRefInput: source.workflow, context });
107
79
  }
108
- if (target.kind === "script")
109
- return directScript(source, baseUnit, target.ref, context);
110
- const action = target.kind === "builtin-command"
111
- ? source.with
112
- : { ref: qualifyRef(target.ref, "commands", context.asset, context.config) };
113
- return commandDispatch(source, baseUnit, action, context);
80
+ // A prose step: its body is the `akm/command` literal content (`parser.ts` `stepSpec`).
81
+ return commandDispatch(source, baseUnit, source.with, context);
114
82
  }
115
83
  /** The gate judge's frozen command target, or undefined when no engine is available and none is configured. */
116
84
  function resolveJudge(source, rubric, context) {
@@ -153,7 +121,6 @@ function frozenRoot(stepId, source, resolved, plan, config) {
153
121
  ...(unit.retry ? { retry: { max: unit.retry.max, on: [...unit.retry.on] } } : {}),
154
122
  onError: unit.onError ?? plan.defaults?.onError ?? "fail",
155
123
  ...(unit.env ? { env: [...unit.env] } : {}),
156
- isolation: unit.isolation ?? "none",
157
124
  source: { ...source.source },
158
125
  frozenTarget: target,
159
126
  environment: [...resolved.environment],
@@ -1,48 +1,31 @@
1
- // This Source Code Form is subject to the terms of the Mozilla Public
2
- // License, v. 2.0. If a copy of the MPL was not distributed with this
3
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
1
  /**
5
- * The one child-workflow resolver. Both composition forms lower here: a direct
6
- * `uses: workflows/<ref>` step (`via: "direct"`) and a `uses: tasks/<ref>`
7
- * step whose task targets a workflow (`via: "task"`). It resolves the child,
8
- * refuses a composition cycle, freezes the child completely through the
9
- * injected `ResolutionContext.freezeChild`, binds the step's inputs against
10
- * the child's `params:`, and embeds the frozen child plan in the target.
2
+ * The one child-workflow resolver (`unit: { workflow: <ref> }`, Experimental).
3
+ * It resolves the child, refuses a composition cycle, freezes the child
4
+ * completely through the injected `ResolutionContext.freezeChild`, binds the
5
+ * step's `with:` against the child's `params:`, and embeds the frozen child
6
+ * plan in the target.
11
7
  */
12
8
  import { createHash } from "node:crypto";
13
9
  import { parseBundleRef } from "../../../core/asset/asset-ref.js";
14
10
  import { UsageError } from "../../../core/errors.js";
15
- import { warn } from "../../../core/warn.js";
16
11
  import { workflowParamContract } from "../../ir/params.js";
17
12
  import { canonicalJson, canonicalPlanJson } from "../../ir/plan-hash.js";
18
13
  import { loadWorkflowAsset } from "../../runtime/workflow-asset-loader.js";
19
14
  import { resolveOwnedAsset } from "../environment.js";
20
15
  import { declaredParamNames, earlierStepIds, } from "../step-values.js";
21
- import { freezeTaskInputBindings, rebindTaskInputBindings } from "../task-bindings.js";
22
- /** The child target's own content identity: its ref, embedded plan hash, route, and bindings. */
16
+ import { freezeTaskInputBindings } from "../task-bindings.js";
17
+ /** The child target's own content identity: its ref, embedded plan hash, and bindings. */
23
18
  function childWorkflowContentHash(fields) {
24
19
  return createHash("sha256")
25
- .update("akm.workflow.child-workflow\0v1\0")
20
+ .update("akm.workflow.child-workflow\0v2\0")
26
21
  .update(canonicalJson({
27
22
  ref: fields.ref,
28
23
  planHash: fields.planHash,
29
- via: fields.via,
30
- taskRef: fields.taskRef ?? null,
31
24
  inputBindings: fields.inputBindings.length > 0 ? fields.inputBindings : null,
32
25
  }))
33
26
  .digest("hex");
34
27
  }
35
- /** A composing step's own `env:` (literal or `unit.env`) cannot reach the child run, so say so. */
36
- function warnIfStepEnvironment(stepId, childRef, source) {
37
- const hasLiteralEnv = Object.keys(source.env ?? {}).length > 0;
38
- const hasEnvRefs = (source.unit?.env ?? []).length > 0;
39
- if (!hasLiteralEnv && !hasEnvRefs)
40
- return;
41
- warn(`Workflow step ${stepId} declares env: while composing ${childRef}: a child run carries its own frozen ` +
42
- `environment inside its own plan, so this composing step's env: (or unit: env:) is not delivered into it ` +
43
- `and has no effect. Set those variables inside ${childRef}'s own source instead.`);
44
- }
45
- /** A workflow entry of a composition `refPath` — the only entries a cycle can close through. */
28
+ /** A workflow entry of a composition `refPath`. */
46
29
  function isWorkflowRef(ref) {
47
30
  try {
48
31
  return parseBundleRef(ref).conceptId.startsWith("workflows/");
@@ -62,62 +45,43 @@ function assertNoCompositionCycle(stepId, childRef, refPath) {
62
45
  "composing itself, directly or through intermediates.");
63
46
  }
64
47
  export async function childWorkflowDispatch(input) {
65
- const { source, baseUnit, childRefInput, context, via, taskRef, authoredInputs } = input;
66
- // resolve + qualify. Resolution failures propagate unchanged,
67
- // in code and shape — the same authority every other
68
- // composition target (command/script/task) already resolves through.
48
+ const { source, baseUnit, childRefInput, context } = input;
49
+ // Resolution failures propagate unchanged, in code and shape — the same
50
+ // authority every other asset reference resolves through.
69
51
  const owned = await resolveOwnedAsset(childRefInput, "workflow", context);
70
52
  const childAsset = await loadWorkflowAsset(owned.ref);
71
53
  const childRef = childAsset.ref;
72
- // Issue 10: an authored env: on the composing step has no path to reach
73
- // the child run — warn rather than vanish silently (see
74
- // warnIfStepEnvironment's doc comment).
75
- warnIfStepEnvironment(source.id, childRef, source);
76
- // the composition cycle check, before any child compilation.
54
+ // The composition cycle check, before any child compilation.
77
55
  assertNoCompositionCycle(source.id, childRef, context.refPath);
78
56
  // Freeze the child completely; its plan is a pure function of its own source.
79
- const childRefPath = via === "task" && taskRef !== undefined ? [...context.refPath, taskRef, childRef] : [...context.refPath, childRef];
80
- const child = await context.freezeChild(childAsset, childRefPath);
57
+ const child = await context.freezeChild(childAsset, [...context.refPath, childRef]);
81
58
  // Embed the child plan as plain canonical JSON, exactly as `plan_json` stores it.
82
59
  const embeddedPlanJson = canonicalPlanJson(child.plan);
83
60
  const frozenPlan = JSON.parse(embeddedPlanJson);
84
- // Bind the step's effective inputs against the child's declared params.
85
- const inputBindings = authoredInputs.kind === "bindings"
86
- ? rebindTaskInputBindings({
87
- stepId: source.id,
88
- targetRef: childRef,
89
- bindings: authoredInputs.value,
90
- contract: workflowParamContract(frozenPlan),
91
- })
92
- : freezeTaskInputBindings({
93
- stepId: source.id,
94
- targetRef: childRef,
95
- with: authoredInputs.value,
96
- contract: workflowParamContract(frozenPlan),
97
- earlierStepIds: earlierStepIds(context.plan, source.id),
98
- declaredParamNames: declaredParamNames(context.plan),
99
- });
100
- // build the frozen target.
61
+ // Bind the step's `with:` against the child's declared params.
62
+ const inputBindings = freezeTaskInputBindings({
63
+ stepId: source.id,
64
+ targetRef: childRef,
65
+ with: source.with,
66
+ contract: workflowParamContract(frozenPlan),
67
+ earlierStepIds: earlierStepIds(context.plan, source.id),
68
+ declaredParamNames: declaredParamNames(context.plan),
69
+ });
101
70
  const planHash = createHash("sha256").update(embeddedPlanJson).digest("hex");
102
- const contentHash = childWorkflowContentHash({ ref: childRef, planHash, via, taskRef, inputBindings });
103
71
  const target = Object.freeze({
104
72
  kind: "child-workflow",
105
73
  ref: childRef,
106
74
  planHash,
107
75
  frozenPlan,
108
- contentHash,
109
- via,
110
- ...(taskRef !== undefined ? { taskRef } : {}),
76
+ contentHash: childWorkflowContentHash({ ref: childRef, planHash, inputBindings }),
111
77
  ...(inputBindings.length > 0 ? { inputBindings } : {}),
112
78
  });
113
79
  return {
114
80
  target,
115
- // A child run carries its own frozen environment inside its own plan.
116
- // A composing step's own env: cannot reach it, so assertNoStepEnvironment
117
- // above rejects one instead of it silently vanishing here.
81
+ // A child run carries its own frozen environment inside its own plan; the
82
+ // parser rejects an `env` beside `workflow`, so there is nothing to deliver.
118
83
  environment: [],
119
84
  unit: baseUnit,
120
- instructions: source.instructions ??
121
- (via === "task" && taskRef !== undefined ? `Run task ${taskRef}.` : `Run workflow ${childRef}.`),
85
+ instructions: source.instructions ?? `Run workflow ${childRef}.`,
122
86
  };
123
87
  }
@@ -2,34 +2,21 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { createHash } from "node:crypto";
5
- import { parseBuiltinCommandAction } from "../../../commands/command/builtin-action.js";
6
5
  import { prepareCommandInvocation } from "../../../commands/command/command-execution.js";
7
- import { PORTABLE_ARGUMENTS_PLACEHOLDER } from "../../../commands/command/portable-template.js";
8
6
  import { captureFrozenDirectoryIdentity } from "../../../execution/directory-identity.js";
9
7
  import { canonicalResolvedExecutionRequest, } from "../../../execution/resolved-request.js";
10
8
  import { fallbackAnnouncement } from "../../../integrations/agent/engine-fallback.js";
11
9
  import { buildExecution } from "../../../integrations/agent/execution.js";
12
10
  import { freezeEnvironment, workflowExecutionSource } from "../environment.js";
13
- import { gitIdentity } from "../identity.js";
14
11
  import { durableRequest, executionUnitValues, targetConcurrency, } from "../step-values.js";
15
- function inlineWorkflowCommandAction(action, commandMode) {
16
- if (commandMode !== "portable-template")
17
- return action;
18
- const parsed = parseBuiltinCommandAction(action);
19
- if (parsed.kind !== "inline")
20
- return action;
21
- return { content: parsed.content.split(PORTABLE_ARGUMENTS_PLACEHOLDER).join(parsed.arguments ?? "") };
22
- }
23
12
  export async function commandDispatch(source, baseUnit, action, context) {
24
13
  const prepared = await prepareCommandInvocation({
25
- action: inlineWorkflowCommandAction(action, source.commandMode),
14
+ action,
26
15
  config: context.config,
27
16
  ...(context.plan.defaults
28
17
  ? { invocationDefaults: executionUnitValues(context.plan.defaults, context.asset.sourcePath) }
29
18
  : {}),
30
- ...(source.commandMode === "literal" || source.commandMode === "portable-template"
31
- ? { inlineContentMode: "literal" }
32
- : {}),
19
+ inlineContentMode: "literal",
33
20
  current: executionUnitValues(source.unit, context.asset.sourcePath),
34
21
  sourceLoader: (ref, kind) => workflowExecutionSource(ref, kind, context),
35
22
  });
@@ -57,7 +44,6 @@ export function commandResult(source, baseUnit, prepared, context, literals = []
57
44
  runner,
58
45
  ...(targetConcurrency(runner, context.config) ? { concurrency: targetConcurrency(runner, context.config) } : {}),
59
46
  cwdIdentity,
60
- ...gitIdentity(baseUnit, cwdIdentity.realRoot),
61
47
  });
62
48
  const engineAnnouncement = fallbackAnnouncement(prepared.fallbackEngineName, request.engine.name);
63
49
  return {