akm-cli 0.9.17-alpha.2 → 0.9.17-alpha.4

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 (343) hide show
  1. package/CHANGELOG.md +756 -0
  2. package/dist/akm +94 -196
  3. package/dist/cli/shared.js +6 -2
  4. package/dist/cli.js +22 -9
  5. package/dist/commands/agent/agent-dispatch.js +1 -1
  6. package/dist/commands/command/command-execution.js +24 -62
  7. package/dist/commands/feedback-cli.js +0 -1
  8. package/dist/commands/health/accept-rate.js +2 -2
  9. package/dist/commands/health/checks.js +30 -75
  10. package/dist/commands/health/config-skew.js +38 -0
  11. package/dist/commands/health/egress.js +54 -0
  12. package/dist/commands/health/html-report.js +0 -38
  13. package/dist/commands/health/improve-metrics.js +123 -562
  14. package/dist/commands/health/plugin-staleness.js +53 -3
  15. package/dist/commands/health/renderers.js +12 -4
  16. package/dist/commands/health/report-view-model.js +11 -106
  17. package/dist/commands/health/types-improve.js +4 -19
  18. package/dist/commands/health/windows.js +64 -73
  19. package/dist/commands/health.js +122 -143
  20. package/dist/commands/improve/consolidate/chunking.js +25 -100
  21. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  22. package/dist/commands/improve/consolidate.js +538 -1075
  23. package/dist/commands/improve/content-hash.js +16 -24
  24. package/dist/commands/improve/distill/content-repair.js +18 -100
  25. package/dist/commands/improve/distill-guards.js +20 -81
  26. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  27. package/dist/commands/improve/distill.js +608 -1075
  28. package/dist/commands/improve/eligibility.js +126 -400
  29. package/dist/commands/improve/execution.js +3 -5
  30. package/dist/commands/improve/extract.js +487 -1046
  31. package/dist/commands/improve/feedback-valence.js +0 -25
  32. package/dist/commands/improve/improve-cli.js +29 -166
  33. package/dist/commands/improve/improve-result-file.js +10 -66
  34. package/dist/commands/improve/improve-strategies.js +12 -7
  35. package/dist/commands/improve/improve-usage-report.js +18 -64
  36. package/dist/commands/improve/improve.js +443 -1063
  37. package/dist/commands/improve/ledger.js +114 -0
  38. package/dist/commands/improve/locks.js +2 -8
  39. package/dist/commands/improve/loop-stages.js +459 -1172
  40. package/dist/commands/improve/memory/derived-ref.js +12 -77
  41. package/dist/commands/improve/memory/memory-belief.js +14 -118
  42. package/dist/commands/improve/memory/memory-improve.js +4 -3
  43. package/dist/commands/improve/outcome-loop.js +28 -156
  44. package/dist/commands/improve/planner.js +5 -10
  45. package/dist/commands/improve/preparation.js +851 -2339
  46. package/dist/commands/improve/proactive-maintenance.js +34 -101
  47. package/dist/commands/improve/reflect-noise.js +104 -280
  48. package/dist/commands/improve/reflect.js +621 -1367
  49. package/dist/commands/improve/salience.js +46 -232
  50. package/dist/commands/improve/session-asset.js +19 -100
  51. package/dist/commands/improve/stage.js +323 -0
  52. package/dist/commands/proposal/drain.js +251 -644
  53. package/dist/commands/proposal/proposal-cli.js +3 -18
  54. package/dist/commands/proposal/proposal-types.js +20 -41
  55. package/dist/commands/proposal/proposal.js +1 -2
  56. package/dist/commands/proposal/propose.js +134 -160
  57. package/dist/commands/proposal/repository.js +502 -1487
  58. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  59. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  60. package/dist/commands/proposal/validators/proposals.js +13 -89
  61. package/dist/commands/read/curate.js +63 -413
  62. package/dist/commands/read/search-cli.js +16 -33
  63. package/dist/commands/read/search.js +17 -23
  64. package/dist/commands/read/show.js +2 -13
  65. package/dist/commands/sources/bundle-cli.js +25 -2
  66. package/dist/commands/sources/bundle-config-ops.js +7 -0
  67. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  68. package/dist/commands/sources/info.js +2 -11
  69. package/dist/commands/sources/installed-stashes.js +197 -746
  70. package/dist/commands/sources/schema-repair.js +98 -129
  71. package/dist/commands/sources/source-add.js +62 -12
  72. package/dist/commands/sources/stash-cli.js +1 -1
  73. package/dist/commands/tasks/explain.js +10 -13
  74. package/dist/commands/tasks/tasks-cli.js +9 -8
  75. package/dist/commands/tasks/tasks.js +326 -930
  76. package/dist/commands/tasks/validate.js +42 -21
  77. package/dist/commands/workflow/plan.js +22 -29
  78. package/dist/commands/workflow-cli.js +4 -4
  79. package/dist/core/adapter/adapters/akm-adapter.js +0 -1
  80. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  81. package/dist/core/adapter/adapters/akm-metadata.js +11 -12
  82. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  83. package/dist/core/adapter/execution-source.js +17 -29
  84. package/dist/core/asset/resolve-ref.js +1 -1
  85. package/dist/core/bundle-id.js +42 -5
  86. package/dist/core/bundle-rename.js +291 -0
  87. package/dist/core/config/config-io.js +1 -2
  88. package/dist/core/config/config-schema.js +1 -33
  89. package/dist/core/config/config-walker.js +1 -1
  90. package/dist/core/config/config.js +163 -68
  91. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  92. package/dist/core/config/schema/embedding.js +20 -5
  93. package/dist/core/config/schema/engines.js +5 -0
  94. package/dist/core/config/schema/execution.js +1 -1
  95. package/dist/core/config/schema/experimental.js +1 -1
  96. package/dist/core/config/schema/improve-processes.js +21 -95
  97. package/dist/core/config/schema/improve.js +4 -42
  98. package/dist/core/config/schema/scheduler.js +12 -12
  99. package/dist/core/config/schema/search.js +6 -22
  100. package/dist/core/env-secret-ref.js +0 -1
  101. package/dist/core/errors.js +8 -9
  102. package/dist/core/file-lock.js +76 -173
  103. package/dist/core/logs-db.js +2 -2
  104. package/dist/core/paths.js +0 -27
  105. package/dist/core/redaction.js +109 -2
  106. package/dist/core/run-lock.js +2 -5
  107. package/dist/core/spawn-env.js +1 -1
  108. package/dist/core/state/migrations.js +108 -61
  109. package/dist/core/state-db-scope.js +2 -4
  110. package/dist/core/state-db.js +126 -692
  111. package/dist/core/type-presentation.js +1 -9
  112. package/dist/core/write-source.js +293 -1012
  113. package/dist/execution/input-contract.js +1 -1
  114. package/dist/execution/resolved-request.js +135 -689
  115. package/dist/execution/source.js +63 -257
  116. package/dist/execution/target-ref.js +1 -1
  117. package/dist/indexer/bundle-identity-guard.js +2 -2
  118. package/dist/indexer/db/graph-db.js +106 -46
  119. package/dist/indexer/ensure-index.js +44 -85
  120. package/dist/indexer/graph/graph-extraction.js +340 -562
  121. package/dist/indexer/graph/graph-related.js +130 -0
  122. package/dist/indexer/index-rebuild-lock.js +3 -11
  123. package/dist/indexer/index-writer-lock.js +8 -17
  124. package/dist/indexer/index-written-assets.js +139 -151
  125. package/dist/indexer/indexer.js +524 -846
  126. package/dist/indexer/materialize-embeddings.js +60 -397
  127. package/dist/indexer/passes/memory-inference.js +81 -90
  128. package/dist/indexer/passes/metadata.js +132 -200
  129. package/dist/indexer/read-preflight.js +0 -7
  130. package/dist/indexer/scan/doc-to-entry.js +1 -3
  131. package/dist/indexer/scan/drain-dir.js +1 -1
  132. package/dist/indexer/search/db-search.js +181 -590
  133. package/dist/indexer/search/fts-query.js +30 -41
  134. package/dist/indexer/search/ranking.js +28 -154
  135. package/dist/indexer/search/search-attribution.js +12 -32
  136. package/dist/indexer/search/search-fields.js +11 -15
  137. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  138. package/dist/indexer/search/search-source.js +1 -4
  139. package/dist/indexer/usage/usage-events.js +2 -7
  140. package/dist/integrations/agent/engine-fallback.js +23 -40
  141. package/dist/integrations/agent/engine-resolution.js +93 -183
  142. package/dist/integrations/agent/execution.js +507 -0
  143. package/dist/integrations/agent/model-map.js +28 -156
  144. package/dist/integrations/agent/request-lowering.js +66 -141
  145. package/dist/integrations/agent/runner-dispatch.js +143 -321
  146. package/dist/integrations/agent/runner.js +54 -14
  147. package/dist/integrations/lockfile.js +53 -101
  148. package/dist/llm/embedders/deterministic.js +2 -3
  149. package/dist/llm/embedders/profile.js +71 -0
  150. package/dist/llm/embedders/remote.js +10 -15
  151. package/dist/llm/graph-extract.js +3 -12
  152. package/dist/llm/index-passes.js +3 -5
  153. package/dist/llm/memory-infer.js +1 -2
  154. package/dist/llm/metadata-enhance.js +1 -2
  155. package/dist/llm/structured-call.js +5 -24
  156. package/dist/output/generic-render.js +23 -11
  157. package/dist/output/html-render.js +13 -10
  158. package/dist/output/render-registry.js +3 -32
  159. package/dist/output/shapes/helpers.js +2 -34
  160. package/dist/output/shapes/passthrough.js +1 -9
  161. package/dist/{indexer/search/ranking-types.js → output/text/bundle-rename.js} +4 -1
  162. package/dist/output/text/command-format.js +60 -23
  163. package/dist/output/text/helpers.js +1 -1
  164. package/dist/output/text/migrate.js +5 -14
  165. package/dist/output/text/proposal-format.js +1 -2
  166. package/dist/output/text/workflow-format.js +0 -32
  167. package/dist/output/text.js +2 -0
  168. package/dist/registry/factory.js +4 -19
  169. package/dist/registry/network.js +66 -220
  170. package/dist/registry/providers/index.js +0 -2
  171. package/dist/registry/providers/skills-sh.js +3 -14
  172. package/dist/registry/providers/static-index.js +24 -26
  173. package/dist/registry/resolve.js +55 -131
  174. package/dist/scripts/akm-migrate-node.js +43937 -93313
  175. package/dist/scripts/akm-migrate.js +43697 -93071
  176. package/dist/setup/registry-stash-loader.js +4 -13
  177. package/dist/setup/semantic-assets.js +3 -44
  178. package/dist/setup/setup.js +1 -1
  179. package/dist/setup/steps/tasks.js +25 -15
  180. package/dist/sources/provider-factory.js +17 -18
  181. package/dist/sources/providers/filesystem.js +2 -3
  182. package/dist/sources/providers/git-install.js +7 -1
  183. package/dist/sources/providers/git-provider.js +0 -3
  184. package/dist/sources/providers/git-stash.js +0 -17
  185. package/dist/sources/providers/npm.js +2 -4
  186. package/dist/sources/providers/provider-utils.js +5 -10
  187. package/dist/sources/providers/website.js +0 -2
  188. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  189. package/dist/sources/website-url.js +2 -2
  190. package/dist/storage/database.js +9 -35
  191. package/dist/storage/repositories/improve-ledger-repository.js +168 -0
  192. package/dist/storage/repositories/index-connection.js +34 -70
  193. package/dist/storage/repositories/index-entries-repository.js +69 -111
  194. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  195. package/dist/storage/repositories/index-entry-schema.js +83 -269
  196. package/dist/storage/repositories/index-fts-repository.js +86 -256
  197. package/dist/storage/repositories/index-llm-cache-repository.js +17 -0
  198. package/dist/storage/repositories/index-meta-repository.js +6 -4
  199. package/dist/storage/repositories/index-schema.js +192 -220
  200. package/dist/storage/repositories/index-utility-repository.js +8 -29
  201. package/dist/storage/repositories/index-vec-repository.js +133 -414
  202. package/dist/storage/repositories/outcome-repository.js +2 -1
  203. package/dist/storage/repositories/proposals-repository.js +35 -0
  204. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  205. package/dist/storage/repositories/task-history-repository.js +26 -4
  206. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  207. package/dist/storage/sqlite-migrations.js +136 -0
  208. package/dist/storage/sqlite-pragmas.js +11 -9
  209. package/dist/storage/sqlite-transaction.js +170 -0
  210. package/dist/storage/state-db-integrity.js +34 -27
  211. package/dist/tasks/activation-config.js +134 -62
  212. package/dist/tasks/backends/cron.js +129 -277
  213. package/dist/tasks/backends/exec-utils.js +2 -5
  214. package/dist/tasks/backends/launchd.js +125 -745
  215. package/dist/tasks/backends/schtasks.js +101 -620
  216. package/dist/tasks/prepare/prepare-support.js +5 -15
  217. package/dist/tasks/prepare/prepare.js +0 -2
  218. package/dist/tasks/resolve-akm-bin.js +20 -79
  219. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  220. package/dist/tasks/scheduler-binding.js +18 -238
  221. package/dist/tasks/scheduler-invocation.js +52 -52
  222. package/dist/tasks/scheduler-lock.js +53 -0
  223. package/dist/tasks/scheduler-sync.js +363 -679
  224. package/dist/tasks/source/parse-task-source.js +160 -10
  225. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  226. package/dist/tasks/source/task-to-v4.js +2 -2
  227. package/dist/workflows/authoring/authoring.js +3 -12
  228. package/dist/workflows/compile.js +211 -0
  229. package/dist/workflows/concurrency-policy.js +13 -74
  230. package/dist/workflows/exec/child-invocation.js +3 -17
  231. package/dist/workflows/exec/child-workflow.js +32 -141
  232. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  233. package/dist/workflows/exec/environment.js +98 -0
  234. package/dist/workflows/exec/exec-unit.js +33 -140
  235. package/dist/workflows/exec/frozen-judge.js +7 -59
  236. package/dist/workflows/exec/native-executor.js +82 -341
  237. package/dist/workflows/exec/param-secrets.js +29 -47
  238. package/dist/workflows/exec/run-workflow.js +154 -387
  239. package/dist/workflows/exec/scheduler.js +9 -36
  240. package/dist/workflows/exec/step-work.js +127 -430
  241. package/dist/workflows/exec/unit-dispatch.js +11 -63
  242. package/dist/workflows/exec/unit-writer.js +8 -52
  243. package/dist/workflows/exec/worktree.js +39 -273
  244. package/dist/workflows/freeze/child-output-references.js +4 -15
  245. package/dist/workflows/freeze/environment.js +99 -92
  246. package/dist/workflows/freeze/freeze.js +172 -0
  247. package/dist/workflows/freeze/step-values.js +19 -21
  248. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  249. package/dist/workflows/freeze/targets/command.js +10 -33
  250. package/dist/workflows/freeze/targets/script.js +5 -12
  251. package/dist/workflows/freeze/targets/shell.js +3 -6
  252. package/dist/workflows/freeze/targets/task.js +25 -80
  253. package/dist/workflows/freeze/task-bindings.js +20 -67
  254. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  255. package/dist/workflows/ir/params.js +6 -51
  256. package/dist/workflows/ir/plan-hash.js +2 -34
  257. package/dist/workflows/parser.js +140 -43
  258. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  259. package/dist/workflows/renderer.js +36 -69
  260. package/dist/workflows/resource-limits.js +12 -120
  261. package/dist/workflows/runtime/agent-identity.js +8 -40
  262. package/dist/workflows/runtime/run-outputs.js +3 -6
  263. package/dist/workflows/runtime/run-plan.js +316 -0
  264. package/dist/workflows/runtime/runs.js +48 -200
  265. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  266. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  267. package/dist/workflows/validate-summary.js +2 -7
  268. package/docs/integration/bundling-akm.md +49 -42
  269. package/docs/migration/README.md +1 -0
  270. package/docs/migration/release-notes/0.9.17.md +41 -0
  271. package/docs/migration/v0.9.1-to-v0.9.2.md +19 -7
  272. package/docs/reference/cli.md +182 -125
  273. package/docs/reference/configuration.md +49 -56
  274. package/docs/reference/data-and-telemetry.md +19 -20
  275. package/docs/reference/tasks.md +86 -38
  276. package/docs/reference/workflow-schema.md +14 -18
  277. package/docs/reference/workflows.md +6 -9
  278. package/package.json +1 -1
  279. package/schemas/akm-config.json +87 -406
  280. package/dist/commands/health/advisories.js +0 -150
  281. package/dist/commands/health/metrics.js +0 -329
  282. package/dist/commands/health/surfaces.js +0 -102
  283. package/dist/commands/improve/anti-collapse.js +0 -83
  284. package/dist/commands/improve/collapse-detector.js +0 -432
  285. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  286. package/dist/commands/improve/consolidate/merge.js +0 -146
  287. package/dist/commands/improve/distill/promote-memory.js +0 -329
  288. package/dist/commands/improve/distill/quality-gate.js +0 -500
  289. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  290. package/dist/commands/improve/proposal-envelope.js +0 -31
  291. package/dist/commands/improve/run-context.js +0 -123
  292. package/dist/commands/improve/shared.js +0 -21
  293. package/dist/commands/improve/source-identity.js +0 -28
  294. package/dist/commands/improve/triage.js +0 -96
  295. package/dist/commands/proposal/drain-policies.js +0 -151
  296. package/dist/commands/sources/update-transaction.js +0 -220
  297. package/dist/core/action-contributors.js +0 -28
  298. package/dist/core/config/config-version-shim.js +0 -101
  299. package/dist/core/config/retired-experimental-keys-shim.js +0 -62
  300. package/dist/core/fs-txn.js +0 -405
  301. package/dist/core/lexical-score.js +0 -25
  302. package/dist/core/maintenance-barrier.js +0 -167
  303. package/dist/execution/executable-identity.js +0 -105
  304. package/dist/execution/guarded-source.js +0 -427
  305. package/dist/indexer/graph/graph-boost.js +0 -427
  306. package/dist/indexer/graph/graph-dedup.js +0 -95
  307. package/dist/indexer/search/name-match.js +0 -35
  308. package/dist/indexer/search/ranking-contributors.js +0 -515
  309. package/dist/indexer/walk/project-context.js +0 -192
  310. package/dist/integrations/agent/execution-cascade.js +0 -566
  311. package/dist/integrations/agent/execution-definitions.js +0 -202
  312. package/dist/integrations/agent/execution-lowering.js +0 -841
  313. package/dist/integrations/agent/execution-preparation.js +0 -98
  314. package/dist/integrations/agent/inline-execution.js +0 -74
  315. package/dist/registry/create-provider-registry.js +0 -29
  316. package/dist/registry/pinned-request-helper.js +0 -247
  317. package/dist/registry/pinned-transport.js +0 -717
  318. package/dist/sources/providers/index.js +0 -14
  319. package/dist/storage/engines/sqlite-migrations.js +0 -271
  320. package/dist/storage/repositories/canaries-repository.js +0 -107
  321. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  322. package/dist/storage/repositories/registry-cache.js +0 -113
  323. package/dist/tasks/scheduler-sync-preview.js +0 -52
  324. package/dist/workflows/freeze/resolve-steps.js +0 -86
  325. package/dist/workflows/freeze/source-freeze.js +0 -64
  326. package/dist/workflows/ir/compile.js +0 -321
  327. package/dist/workflows/ir/environment-v4.js +0 -330
  328. package/dist/workflows/ir/freeze-v4.js +0 -153
  329. package/dist/workflows/ir/schema-v4.js +0 -745
  330. package/dist/workflows/ir/schema.js +0 -354
  331. package/dist/workflows/program/schema.js +0 -78
  332. package/dist/workflows/runtime/checkin.js +0 -57
  333. package/dist/workflows/runtime/plan-classifier.js +0 -196
  334. package/dist/workflows/runtime/unit-checkin.js +0 -45
  335. package/dist/workflows/runtime/unit-phases.js +0 -20
  336. package/dist/workflows/schema.js +0 -4
  337. package/dist/workflows/source-ir/compile.js +0 -200
  338. package/dist/workflows/source-ir/program.js +0 -50
  339. package/dist/workflows/source-ir/result.js +0 -26
  340. package/dist/workflows/source-ir/schema.js +0 -786
  341. package/dist/workflows/source-ir/triggers.js +0 -79
  342. package/dist/workflows/source-ir/uses.js +0 -40
  343. package/dist/workflows/validator.js +0 -60
@@ -1,113 +0,0 @@
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
- import { rethrowIfTestIsolationError } from "../../core/errors.js";
5
- import { formatRegistryError } from "../../core/registry-url.js";
6
- import { warn } from "../../core/warn.js";
7
- import { closeDatabase, openIndexDatabase } from "./index-connection.js";
8
- import { getRegistryIndexCache, upsertRegistryIndexCache } from "./registry-index-cache-repository.js";
9
- /**
10
- * RAII-style lifecycle helper for the registry cache DB. Opens the DB (treating
11
- * a failed open exactly like the legacy fall-through: the bun-test isolation
12
- * guard is re-thrown, any other failure yields `db = undefined`), runs `fn`,
13
- * and guarantees the DB is closed in a `finally` after `fn` has fully settled
14
- * (the await is required: the callbacks are async, and closing before they
15
- * settle would tear the DB down mid-write).
16
- */
17
- export async function withRegistryCacheDb(fn) {
18
- let db;
19
- try {
20
- db = openIndexDatabase();
21
- }
22
- catch (err) {
23
- // Never mask the bun-test isolation guard as "DB unavailable".
24
- rethrowIfTestIsolationError(err);
25
- db = undefined;
26
- }
27
- try {
28
- return await fn(db);
29
- }
30
- finally {
31
- if (db) {
32
- try {
33
- closeDatabase(db);
34
- }
35
- catch {
36
- /* ignore */
37
- }
38
- }
39
- }
40
- }
41
- /**
42
- * Shared registry index-cache fetch template. Opens the cache DB, returns a
43
- * fresh cache hit when present, otherwise fetches live (writing the result back
44
- * to the cache best-effort), and falls back to a stale cache row when the fetch
45
- * fails. Behaviour-preserving extraction of the logic previously duplicated in
46
- * `skills-sh.ts` (`fetchSkills`) and `static-index.ts` (`loadIndex`).
47
- */
48
- export async function fetchCachedJson(opts) {
49
- const { cacheKey, ttlMs, parseCache, fetchFresh } = opts;
50
- return withRegistryCacheDb(async (db) => {
51
- // ── Step 1: Try DB cache (index.db) ─────────────────────────────────────
52
- let dbCacheResult;
53
- try {
54
- if (db) {
55
- dbCacheResult = getRegistryIndexCache(db, cacheKey, ttlMs);
56
- }
57
- }
58
- catch (err) {
59
- // Never mask the bun-test isolation guard as "DB unavailable" — see
60
- // rethrowIfTestIsolationError in src/core/errors.ts. Without this, a
61
- // leaky test silently gets a cold cache instead of the loud
62
- // TEST_ISOLATION_MISSING failure the guard intends.
63
- rethrowIfTestIsolationError(err);
64
- // index.db read failed (pre-migration install or test env) — fall through
65
- }
66
- if (dbCacheResult) {
67
- const cached = parseCache(dbCacheResult.indexJson, { stale: false });
68
- if (cached !== undefined) {
69
- return cached;
70
- }
71
- }
72
- // ── Step 2: Fetch fresh ──────────────────────────────────────────────────
73
- try {
74
- const { value, cacheJson, cacheOpts } = await fetchFresh(db);
75
- if (db) {
76
- try {
77
- upsertRegistryIndexCache(db, cacheKey, cacheJson, cacheOpts);
78
- }
79
- catch {
80
- /* best-effort */
81
- }
82
- }
83
- return value;
84
- }
85
- catch (err) {
86
- // Fetch failed — use stale DB cache if available.
87
- if (dbCacheResult) {
88
- const stale = parseCache(dbCacheResult.indexJson, { stale: true });
89
- if (stale !== undefined)
90
- return stale;
91
- }
92
- // No in-TTL row — consult the cache PAST its TTL before giving up
93
- // (§24.2 "Durability" gate): a briefly unreachable registry should
94
- // degrade to the last-known index, loudly, not hard-fail the command.
95
- try {
96
- const expiredRow = db ? getRegistryIndexCache(db, cacheKey, Number.POSITIVE_INFINITY) : undefined;
97
- if (expiredRow) {
98
- const stale = parseCache(expiredRow.indexJson, { stale: true });
99
- if (stale !== undefined) {
100
- warn(`Registry fetch failed (${formatRegistryError(err)}); ` +
101
- "serving the last cached index, which is past its refresh interval.");
102
- return stale;
103
- }
104
- }
105
- }
106
- catch (cacheErr) {
107
- rethrowIfTestIsolationError(cacheErr);
108
- // cache read failed — fall through to the original fetch error
109
- }
110
- throw err;
111
- }
112
- });
113
- }
@@ -1,52 +0,0 @@
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
- /**
5
- * Project a set of scheduler sync operations into a preview report. Pure:
6
- * no I/O, no backend calls. Accepts a bare operation array (not the whole
7
- * `SchedulerSyncPlan`) so a future `task prune` can build a preview from
8
- * its own remove-only operation set without needing a full sync plan.
9
- */
10
- export function renderSchedulerPlanPreview(backend, operations, unchanged = [], failures = []) {
11
- const adds = [];
12
- const updates = [];
13
- const removes = [];
14
- for (const operation of operations) {
15
- if (operation.kind === "remove") {
16
- removes.push({
17
- id: operation.id,
18
- kind: "remove",
19
- nativeId: operation.nativeId,
20
- ...(operation.ownerBundlePath !== undefined ? { ownerBundlePath: operation.ownerBundlePath } : {}),
21
- ...(operation.reason !== undefined ? { reason: operation.reason } : {}),
22
- });
23
- }
24
- else if (operation.kind === "install") {
25
- adds.push({ id: operation.binding.id, kind: "install" });
26
- }
27
- else {
28
- updates.push({
29
- id: operation.binding.id,
30
- kind: "update",
31
- ...(operation.expected.fingerprint !== undefined
32
- ? { installedFingerprint: operation.expected.fingerprint }
33
- : {}),
34
- ...(operation.resultFingerprint !== undefined ? { expectedFingerprint: operation.resultFingerprint } : {}),
35
- });
36
- }
37
- }
38
- return Object.freeze({
39
- backend,
40
- dryRun: true,
41
- adds: Object.freeze(adds),
42
- updates: Object.freeze(updates),
43
- removes: Object.freeze(removes),
44
- unchanged: Object.freeze([...unchanged]),
45
- hasRemovals: removes.length > 0,
46
- failures: Object.freeze([...failures]),
47
- });
48
- }
49
- /** Convenience wrapper for the common case: previewing a whole {@link SchedulerSyncPlan}. */
50
- export function renderSchedulerSyncPlanPreview(backend, plan) {
51
- return renderSchedulerPlanPreview(backend, plan.operations, plan.unchanged, plan.failures);
52
- }
@@ -1,86 +0,0 @@
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
- import { ConfigError, UsageError } from "../../core/errors.js";
5
- import { prepareInlineExecution } from "../../integrations/agent/inline-execution.js";
6
- import { sourceStepProgramUnit, sourceStepRef } from "../source-ir/program.js";
7
- import { classifyWorkflowStepUses } from "../source-ir/semantics.js";
8
- import { qualifyRef } from "./environment.js";
9
- import { childWorkflowDispatch } from "./targets/child-workflow.js";
10
- import { commandDispatch, commandResult, inlineDispatch } from "./targets/command.js";
11
- import { directScript } from "./targets/script.js";
12
- import { directShell } from "./targets/shell.js";
13
- import { taskDispatch } from "./targets/task.js";
14
- export async function resolveStep(source, context) {
15
- const baseUnit = sourceStepProgramUnit(source);
16
- if (source.exec || source.run !== undefined)
17
- return directShell(source, baseUnit, context);
18
- if (!source.uses)
19
- return inlineDispatch(source, baseUnit, context);
20
- const target = classifyWorkflowStepUses(source.uses);
21
- if (target.kind === "task")
22
- return taskDispatch(source, baseUnit, target.ref, context);
23
- // A direct `uses: workflows/<ref>` step (spec docs/plans/specs/
24
- // p3a-plan-v5-child-freeze.md §4.2, row B-01/B-04). `with:` on this target
25
- // IS a valid binding surface (A-N8) — unlike scripts/commands below,
26
- // `rejectNonTaskBindingWith` must NOT be extended to it.
27
- if (target.kind === "workflow") {
28
- return childWorkflowDispatch({
29
- source,
30
- baseUnit,
31
- childRefInput: target.ref,
32
- context,
33
- via: "direct",
34
- authoredInputs: { kind: "with", value: source.with },
35
- });
36
- }
37
- if (target.kind === "script") {
38
- rejectNonTaskBindingWith(source, target.ref, "script");
39
- return directScript(source, baseUnit, target.ref, context);
40
- }
41
- if (target.kind === "command" || target.kind === "builtin-command") {
42
- if (target.kind === "command")
43
- rejectNonTaskBindingWith(source, target.ref, "command");
44
- const action = target.kind === "builtin-command"
45
- ? source.with
46
- : { ref: qualifyRef(target.ref, "commands", context.asset, context.config) };
47
- return commandDispatch(source, baseUnit, action, context);
48
- }
49
- throw new UsageError(`Workflow target ${source.uses} is not executable in 0.9.2.`, "WORKFLOW_SOURCE_INVALID");
50
- }
51
- /**
52
- * A-N5 (spec docs/plans/specs/p2b-input-bindings.md §1.7): `commands/<ref>`
53
- * and `scripts/<ref>` are not binding surfaces — a `with:` authored on either
54
- * now fails closed instead of being silently dropped (the same defect P1a
55
- * closed for `tasks/<ref>`, now repeated for these two targets, B-22/B-23).
56
- * `akm/command`'s `with:` is its own argument bag
57
- * (`parseBuiltinCommandAction`) and never routes through here.
58
- */
59
- function rejectNonTaskBindingWith(source, ref, kind) {
60
- if (source.with === undefined)
61
- return;
62
- const family = kind === "command" ? "commands" : "scripts";
63
- throw new UsageError(`Workflow step ${source.id} cannot pass with: to ${family} target ${ref}; a ${kind} ref is not a binding surface.`, "COMPOSITION_INVALID");
64
- }
65
- const NO_ENGINE_AVAILABLE_MESSAGE = "the fixed opencode-sdk fallback is unavailable";
66
- function isNoEngineAvailable(err) {
67
- return err instanceof ConfigError && err.message.includes(NO_ENGINE_AVAILABLE_MESSAGE);
68
- }
69
- export function resolveJudge(source, context) {
70
- const configuredEngine = context.config.workflow?.judgeEngine;
71
- const content = source.gate?.rubric?.trim() ?? "Judge workflow completion.";
72
- try {
73
- const prepared = prepareInlineExecution({
74
- content,
75
- config: context.config,
76
- invocationKind: "workflow",
77
- ...(configuredEngine ? { current: { engine: configuredEngine } } : {}),
78
- });
79
- return commandResult(source, { onError: "fail", source: sourceStepRef(source) }, prepared, context);
80
- }
81
- catch (err) {
82
- if (configuredEngine || !isNoEngineAvailable(err))
83
- throw err;
84
- return undefined;
85
- }
86
- }
@@ -1,64 +0,0 @@
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
- import { COMPOSITION_INVALID_MULTI_JOB_HINT, UsageError } from "../../core/errors.js";
5
- import { warn } from "../../core/warn.js";
6
- import { compileWorkflowSource } from "../source-ir/compile.js";
7
- import { resolveJudge, resolveStep } from "./resolve-steps.js";
8
- /**
9
- * Resolve every authored target through the shared command/task authorities
10
- * before v4 publication.
11
- *
12
- * `composition` and `freezeChild` (spec docs/plans/specs/
13
- * p3a-plan-v5-child-freeze.md §4.1/§4.3) thread the recursive
14
- * child-workflow-freeze state down into every step's `ResolutionContext`;
15
- * `ir/freeze-v4.ts`'s `compileResolveFreezeWorkflowV4` is this function's
16
- * ONLY caller (directly — P4 deleted the `ir/source-freeze-v4.ts` shim that
17
- * used to sit on this edge) and supplies both — the root default
18
- * composition, or the composition
19
- * `targets/child-workflow.ts` built for a recursive child freeze.
20
- */
21
- export async function resolveWorkflowSourceV4(asset, workflowSource, config, collector, composition, freezeChild) {
22
- const compiled = compileWorkflowSource(workflowSource.content, { path: asset.path, workspaceRoot: asset.sourcePath });
23
- if (!compiled.ok) {
24
- // P4-N2 (docs/plans/specs/p4-deletions-closeout.md §3.3.4): a compile
25
- // result whose single error is the adapter's multi-job rejection
26
- // surfaces as COMPOSITION_INVALID — one authoritative composition
27
- // policy; every other compile failure (a YAML syntax error, an
28
- // unsupported trigger, …) is WORKFLOW_SOURCE_INVALID. Never blanket-recode.
29
- const isMultiJob = compiled.errors.length === 1 && compiled.errors[0]?.code === "multi-job-unsupported";
30
- const code = isMultiJob ? "COMPOSITION_INVALID" : "WORKFLOW_SOURCE_INVALID";
31
- throw new UsageError(`Workflow source cannot be frozen: ${compiled.errors.map((error) => error.message).join("; ")}`, code, isMultiJob ? COMPOSITION_INVALID_MULTI_JOB_HINT : undefined);
32
- }
33
- const context = { asset, config, collector, sourceIr: compiled.ir, composition, freezeChild };
34
- const units = new Map();
35
- const judges = new Map();
36
- let engineAnnouncement;
37
- const sourceSteps = compiled.ir.jobs[0]?.steps ?? [];
38
- for (const sourceStep of sourceSteps) {
39
- if (!sourceStep.route) {
40
- const resolved = await resolveStep(sourceStep, context);
41
- units.set(sourceStep.id, Object.freeze(resolved));
42
- engineAnnouncement ??= resolved.engineAnnouncement;
43
- }
44
- if (sourceStep.gate?.rubric?.trim()) {
45
- const judge = resolveJudge(sourceStep, context);
46
- if (judge === undefined) {
47
- warn(`Workflow step "${sourceStep.id}" has completion criteria but no verification engine is available ` +
48
- "(set workflow.judgeEngine, defaults.engine, or install an opencode-sdk binary). The step will block " +
49
- "for `akm workflow resume` once it is reached.");
50
- continue;
51
- }
52
- if (judge.target.kind !== "command")
53
- throw new Error(`workflow judge ${sourceStep.id} did not resolve to a command target`);
54
- judges.set(sourceStep.id, judge.target);
55
- engineAnnouncement ??= judge.engineAnnouncement;
56
- }
57
- }
58
- return Object.freeze({
59
- sourceIr: compiled.ir,
60
- units,
61
- judges,
62
- ...(engineAnnouncement ? { engineAnnouncement } : {}),
63
- });
64
- }
@@ -1,321 +0,0 @@
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
- /**
5
- * Frontend -> unresolved workflow plan compiler (workflow-format-unification).
6
- *
7
- * ONE frontend now: {@link compileWorkflowPlan} lowers adapter-neutral source
8
- * IR into the current unresolved plan draft. Markdown and YAML never reach a
9
- * format-specific runtime compiler. This pass owns the
10
- * semantic rules the parser deliberately does not check:
11
- *
12
- * - every reference string (`map.over` / `route.input` / `inputs[]`) parses
13
- * against the CLOSED two-root grammar (`program/expressions.ts`);
14
- * - `steps.<id>` references name an EARLIER step (a producer that has
15
- * already run when the reference resolves);
16
- * - `inputs:` entries must reference a STEP OUTPUT, never `params.*` — params
17
- * are already attached to every unit unconditionally, so naming one as a
18
- * declared input would be redundant.
19
- *
20
- * Node-id convention (stable, unique within a plan):
21
- * step root → `<stepId>` (unit) or `<stepId>.map` (map)
22
- * map unit → `<stepId>.unit` (template instantiated per item)
23
- * gate → `<stepId>.gate`
24
- *
25
- * Returns accumulated `WorkflowError`s rather than throwing. Pure and
26
- * deterministic: the same document always compiles to the same plan.
27
- */
28
- import { compareCodePoints } from "../../core/common.js";
29
- import { formatReference, parseReference } from "../program/expressions.js";
30
- import { projectExecCore } from "../program/schema.js";
31
- import { sourceStepInstructions, sourceStepProgramUnit, sourceStepRef } from "../source-ir/program.js";
32
- import { decodeWorkflowSourceIrV1, } from "../source-ir/schema.js";
33
- /**
34
- * Compile source IR into a frozen-plan-ready graph.
35
- * `title` is the run-level display title (the asset's canonical name — the
36
- * format carries no authored title). Assumes the document came out of
37
- * `parseWorkflow` ok (structure already valid).
38
- */
39
- export function compileWorkflowPlan(input, title, resolvedUnits = new Map()) {
40
- const sourceIr = decodeWorkflowSourceIrV1(input);
41
- const errors = [];
42
- // The decoder guarantees exactly one job (P4 §3.3, docs/plans/specs/
43
- // p4-deletions-closeout.md, row B-43) — a 2+-job document is rejected at
44
- // the adapter boundary and never reaches this compiler.
45
- const sourceSteps = sourceIr.jobs[0]?.steps ?? [];
46
- const allStepIds = new Set(sourceSteps.map((step) => step.id));
47
- const earlierStepIds = new Set();
48
- const steps = [];
49
- sourceSteps.forEach((step, sequenceIndex) => {
50
- const check = { allStepIds, earlierStepIds, errors };
51
- if (step.map) {
52
- checkReferenceField(step.map.over, { ...check, line: step.source.start, label: `Step "${step.id}" map.over` });
53
- }
54
- if (step.route) {
55
- checkReferenceField(step.route.input, {
56
- ...check,
57
- line: step.source.start,
58
- label: `Step "${step.id}" route.input`,
59
- });
60
- }
61
- for (const [index, reference] of (step.inputs ?? []).entries()) {
62
- checkInputReference(reference, index, {
63
- ...check,
64
- line: step.source.start,
65
- label: `Step "${step.id}" inputs`,
66
- });
67
- }
68
- steps.push(compileStep(step, sequenceIndex, sourceIr.defaults, resolvedUnits.get(step.id)));
69
- earlierStepIds.add(step.id);
70
- });
71
- // P3b (spec §4.2, rows B-06/B-07): `outputs:` references are validated
72
- // against the FULL step id set (never `earlierStepIds` — resolution happens
73
- // at RUN COMPLETION, after every step has run, so an output may legitimately
74
- // name any declared step regardless of its position).
75
- for (const [name, declaration] of Object.entries(sourceIr.outputs ?? {})) {
76
- checkOutputReference(name, declaration.from, { errors, allStepIds, line: sourceIr.source.start });
77
- }
78
- if (errors.length > 0)
79
- return { ok: false, errors };
80
- const paramNames = sourceIr.params ? Object.keys(sourceIr.params) : [];
81
- return {
82
- ok: true,
83
- warnings: collectWorkflowWarnings(sourceIr),
84
- plan: {
85
- title,
86
- ...(paramNames.length > 0 ? { params: paramNames } : {}),
87
- ...(sourceIr.params && paramNames.length > 0
88
- ? { paramSchemas: sourceIr.params }
89
- : {}),
90
- ...(sourceIr.outputs ? { outputs: sortedOutputs(sourceIr.outputs) } : {}),
91
- ...(sourceIr.budget
92
- ? {
93
- budget: {
94
- ...(sourceIr.budget.maxTokens !== undefined ? { maxTokens: sourceIr.budget.maxTokens } : {}),
95
- ...(sourceIr.budget.maxUnits !== undefined ? { maxUnits: sourceIr.budget.maxUnits } : {}),
96
- },
97
- }
98
- : {}),
99
- steps,
100
- },
101
- };
102
- }
103
- /**
104
- * Re-key `outputs:` into canonical wire order (code-point-ascending by name)
105
- * — the order {@link decodeWorkflowOutputs} in `ir/schema-v4.ts` requires,
106
- * mirroring how `freeze/task-bindings.ts`'s `finalizeBindings` sorts
107
- * `inputBindings` before freezing. The source parser preserves AUTHOR order
108
- * (P3b spec §4.2 places no ordering requirement on authoring), so this is the
109
- * one place that must impose it.
110
- */
111
- function sortedOutputs(outputs) {
112
- const sorted = {};
113
- for (const name of Object.keys(outputs).sort(compareCodePoints)) {
114
- sorted[name] = outputs[name];
115
- }
116
- return sorted;
117
- }
118
- function compileStep(step, sequenceIndex, defaults, resolved) {
119
- const gate = {
120
- kind: "gate",
121
- id: `${step.id}.gate`,
122
- stepId: step.id,
123
- // The body `### gate` rubric is carried through as the ONE criterion string
124
- // — the judge receives the whole section byte-exact (spec §2.4). A step
125
- // with no rubric needs no verification (criteria: []).
126
- criteria: step.gate?.rubric?.trim() ? [step.gate.rubric] : [],
127
- ...(step.gate?.maxLoops !== undefined ? { maxLoops: step.gate.maxLoops } : {}),
128
- };
129
- let root;
130
- if (step.route === undefined) {
131
- const unit = resolved?.unit ?? sourceStepProgramUnit(step);
132
- const instructionsText = resolved?.instructions ?? sourceStepInstructions(step);
133
- if (step.map) {
134
- root = {
135
- kind: "map",
136
- id: `${step.id}.map`,
137
- over: step.map.over,
138
- template: compileUnit(unit, `${step.id}.unit`, instructionsText, defaults, step.inputs, sourceStepRef(step)),
139
- ...(step.map.concurrency !== undefined ? { concurrency: step.map.concurrency } : {}),
140
- reducer: step.map.reducer ?? "collect",
141
- source: step.source,
142
- };
143
- }
144
- else {
145
- root = compileUnit(unit, step.id, instructionsText, defaults, step.inputs, sourceStepRef(step));
146
- }
147
- }
148
- return {
149
- stepId: step.id,
150
- title: step.id,
151
- sequenceIndex,
152
- ...(root ? { root } : {}),
153
- ...(step.route
154
- ? {
155
- route: {
156
- input: step.route.input,
157
- when: Object.fromEntries(step.route.branches.map((b) => [b.match, b.stepId])),
158
- ...(step.route.defaultStepId !== undefined ? { defaultStepId: step.route.defaultStepId } : {}),
159
- },
160
- }
161
- : {}),
162
- ...(step.output !== undefined ? { outputSchema: step.output } : {}),
163
- gate,
164
- };
165
- }
166
- /**
167
- * Lower one source unit into the unresolved structural plan. Instructions are
168
- * ALWAYS the step's body prose, byte-exact — never templated, never scanned
169
- * for reference syntax. Engine/model/timeout settings remain on the parsed
170
- * override bag until the single freeze boundary.
171
- */
172
- function compileUnit(unit, id, instructions, defaults, inputs, source) {
173
- return {
174
- kind: "unit",
175
- id,
176
- instructions,
177
- ...(inputs && inputs.length > 0 ? { inputs: [...inputs] } : {}),
178
- // Shared projection: named pass-through scope is carried conditionally;
179
- // whole-process environment inheritance is not an authoring surface.
180
- ...(unit.exec ? { exec: projectExecCore(unit.exec) } : {}),
181
- ...(unit.output !== undefined ? { schema: unit.output } : {}),
182
- ...(unit.retry ? { retry: { max: unit.retry.max, on: [...unit.retry.on] } } : {}),
183
- onError: unit.onError ?? defaults?.onError ?? "fail",
184
- ...(unit.env ? { env: [...unit.env] } : {}),
185
- ...(unit.isolation !== undefined ? { isolation: unit.isolation } : {}),
186
- ...(source ? { source } : {}),
187
- };
188
- }
189
- /** Validate a whole-value reference field (`map.over`, `route.input`). */
190
- function checkReferenceField(text, check) {
191
- const parsed = parseReference(text);
192
- if (!parsed.ok) {
193
- check.errors.push({ line: check.line, message: `${check.label}: ${parsed.message}` });
194
- return;
195
- }
196
- if (parsed.expr.kind === "stepOutput" && !check.earlierStepIds.has(parsed.expr.stepId)) {
197
- const why = check.allStepIds.has(parsed.expr.stepId)
198
- ? `step "${parsed.expr.stepId}" does not come before this step — references must name an earlier step (a producer that has already run)`
199
- : `"${parsed.expr.stepId}" is not a step in this workflow`;
200
- check.errors.push({
201
- line: check.line,
202
- message: `${check.label}: "${formatReference(parsed.expr)}" cannot be resolved — ${why}.`,
203
- });
204
- }
205
- }
206
- /** Validate one `inputs[]` entry: must be a step-output reference to an earlier step. */
207
- function checkInputReference(text, index, check) {
208
- const parsed = parseReference(text);
209
- if (!parsed.ok) {
210
- check.errors.push({ line: check.line, message: `${check.label}[${index}]: ${parsed.message}` });
211
- return;
212
- }
213
- if (parsed.expr.kind === "param") {
214
- check.errors.push({
215
- line: check.line,
216
- message: `${check.label}[${index}]: "${formatReference(parsed.expr)}" names a param, not a step output — ` +
217
- `params are already attached to every unit, so declaring one as an input is redundant. "inputs:" only ` +
218
- `names step outputs (steps.<id>.output...).`,
219
- });
220
- return;
221
- }
222
- if (!check.earlierStepIds.has(parsed.expr.stepId)) {
223
- const why = check.allStepIds.has(parsed.expr.stepId)
224
- ? `step "${parsed.expr.stepId}" does not come before this step — references must name an earlier step (a producer that has already run)`
225
- : `"${parsed.expr.stepId}" is not a step in this workflow`;
226
- check.errors.push({
227
- line: check.line,
228
- message: `${check.label}[${index}]: "${formatReference(parsed.expr)}" cannot be resolved — ${why}.`,
229
- });
230
- }
231
- }
232
- /**
233
- * Validate one `outputs.<name>.from` reference (P3b, spec §4.2, rows
234
- * B-06/B-07): it must parse, it must name a STEP output — never a param (an
235
- * output projects a step artifact; a param is already on the run row) — and
236
- * that step must be DECLARED somewhere in the document. Unlike
237
- * {@link checkInputReference}, the named step need not be EARLIER: an output
238
- * resolves at run completion, after every step has already run.
239
- */
240
- function checkOutputReference(name, text, check) {
241
- const parsed = parseReference(text);
242
- if (!parsed.ok) {
243
- check.errors.push({ line: check.line, message: `Output "${name}" from: ${parsed.message}` });
244
- return;
245
- }
246
- if (parsed.expr.kind === "param") {
247
- check.errors.push({
248
- line: check.line,
249
- message: `Output "${name}" from: "${formatReference(parsed.expr)}" names a param, not a step output — an output ` +
250
- `projects a STEP artifact, never a param. "outputs:" only names step outputs (steps.<id>.output...).`,
251
- });
252
- return;
253
- }
254
- if (!check.allStepIds.has(parsed.expr.stepId)) {
255
- check.errors.push({
256
- line: check.line,
257
- message: `Output "${name}" from: "${formatReference(parsed.expr)}" cannot be resolved — "${parsed.expr.stepId}" is ` +
258
- `not a step in this workflow.`,
259
- });
260
- }
261
- }
262
- // ── Non-fatal warnings ───────────────────────────────────────────────────────
263
- /**
264
- * Collect the document's non-fatal WARNINGS — advisories that never fail
265
- * compilation, never change the frozen plan or its hash, and are surfaced as
266
- * `workflow-warning` entries in `akm lint`'s separate `warnings` channel
267
- * (human + JSON output, via `core/adapter/adapters/akm-lint.ts#
268
- * workflowCompileWarnings`) and as `warn()` lines at `workflow run`.
269
- *
270
- * A. A `params.<name>` reference (in `map.over`/`route.input`) to an
271
- * UNDECLARED param, but ONLY when the document declares a `params:`
272
- * block — a likely typo. Prose can no longer carry param references at
273
- * all (it is never scanned), so this warning's surface shrinks to the
274
- * two whole-value fields that can legally contain one.
275
- * B. `gate.max_loops` above 1 on an `exec` step. The engine judges such a
276
- * step but never loops it (`exec/step-work.ts#effectiveGateMaxLoops`):
277
- * a frozen argv cannot read the judge's feedback, so a second loop would
278
- * only re-run the identical command — and its side effects. The declared
279
- * budget is not silently different from what runs; say so.
280
- */
281
- export function collectWorkflowWarnings(input) {
282
- const sourceIr = decodeWorkflowSourceIrV1(input);
283
- const warnings = [];
284
- const declaredParams = sourceIr.params ? new Set(Object.keys(sourceIr.params)) : undefined;
285
- for (const job of sourceIr.jobs) {
286
- for (const step of job.steps) {
287
- const maxLoops = step.gate?.maxLoops ?? 1;
288
- const execUnit = step.exec ?? step.run;
289
- if (maxLoops > 1 && execUnit && step.gate?.rubric?.trim()) {
290
- warnings.push({
291
- line: step.source.start,
292
- message: `Step "${step.id}" declares \`gate.max_loops: ${maxLoops}\` on an \`exec\` step — it runs its command ` +
293
- `ONCE. A gate loop re-executes the step so it can address the judge's feedback, and a frozen argv cannot ` +
294
- `read that feedback; looping would only repeat the command's side effects. The gate still evaluates and ` +
295
- `can still fail the step.`,
296
- });
297
- }
298
- if (declaredParams) {
299
- const declaredList = [...declaredParams].join(", ");
300
- const scan = (text, label) => {
301
- if (!text)
302
- return;
303
- const parsed = parseReference(text);
304
- if (!parsed.ok || parsed.expr.kind !== "param" || declaredParams.has(parsed.expr.name))
305
- return;
306
- warnings.push({
307
- line: step.source.start,
308
- message: `${label}: "${formatReference(parsed.expr)}" references a param not declared in \`params:\` ` +
309
- `(declared: ${declaredList || "none"}) — likely a typo. An undeclared param supplied at start still ` +
310
- `resolves at run time.`,
311
- });
312
- };
313
- if (step.map)
314
- scan(step.map.over, `Step "${step.id}" map.over`);
315
- if (step.route)
316
- scan(step.route.input, `Step "${step.id}" route.input`);
317
- }
318
- }
319
- }
320
- return warnings;
321
- }