akm-cli 0.9.0-rc.8 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -18,7 +18,7 @@ function parseIso(value) {
18
18
  * Pure stale-unit evaluator. Returns every `running` DISPATCH unit whose last
19
19
  * heartbeat (`last_checkin_at`, else the first-claim `started_at`) is older than
20
20
  * `staleMs`. Gate-evaluation rows (`phase = "gate"`) are excluded — they are
21
- * synchronous engine judge calls, never driver-claimed work. A running row with
21
+ * synchronous engine judge calls, never separately claimed work. A running row with
22
22
  * no usable timestamp at all is treated as stale (a claim we can no longer age).
23
23
  * Deterministic in `now` — free of timer flakiness.
24
24
  */
@@ -3,8 +3,8 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
5
  * Unit-row phase markers — a leaf module (imports nothing) so both the exec
6
- * drivers (step-work, brief, run-workflow) and the runtime (unit-checkin) can
7
- * key on the phase discriminator without an exec ↔ runtime import cycle.
6
+ * modules (step-work, run-workflow) and the runtime (unit-checkin) can key on
7
+ * the phase discriminator without an exec ↔ runtime import cycle.
8
8
  * Extracting {@link GATE_EVALUATION_PHASE} here broke the last workflows-
9
9
  * runtime knot (step-work → runs → unit-checkin → step-work; chunk-8 WI-8.6,
10
10
  * DoD 11).
@@ -2,32 +2,43 @@
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 fs from "node:fs";
5
- import { parseRefInput } from "../../core/asset/resolve-ref.js";
6
- import { resolveStashDir } from "../../core/common.js";
5
+ import path from "node:path";
6
+ import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
7
+ import { adapterForId } from "../../core/adapter/registry.js";
8
+ import { makeBundleRef, parseBundleRef } from "../../core/asset/asset-ref.js";
9
+ import { isWithin } from "../../core/common.js";
7
10
  import { loadConfig } from "../../core/config/config.js";
8
11
  import { NotFoundError, UsageError } from "../../core/errors.js";
9
12
  import { getDbPath } from "../../core/paths.js";
10
- import { canonicalizeWorkflowName } from "../../core/recognition-util.js";
13
+ import { canonicalizeWorkflowName, WORKFLOW_EXTENSIONS } from "../../core/recognition-util.js";
14
+ import { deriveInstallations } from "../../indexer/installations.js";
11
15
  import { resolveSourceEntries } from "../../indexer/search/search-source.js";
12
- import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
16
+ import { buildFileContext } from "../../indexer/walk/file-context.js";
13
17
  import { resolveAssetPath } from "../../sources/resolve.js";
14
18
  import { withIndexDb } from "../../storage/repositories/index-db.js";
15
19
  import { formatWorkflowErrors } from "../authoring/authoring.js";
16
20
  import { parseWorkflow } from "../parser.js";
17
- import { parseWorkflowProgram } from "../program/parser.js";
18
- import { isWorkflowProgramPath, projectProgramParameters, projectProgramStepDefinitions } from "../program/project.js";
21
+ import { WORKFLOW_SCHEMA_VERSION } from "../schema.js";
19
22
  /**
20
- * The canonical durable `workflow_runs.workflow_ref` run-key:
21
- * `[origin//]workflows/<canonical-name>` (normative §11.4 — the chunk-8
22
- * cutover re-keys pre-existing legacy rows onto this spelling; every mint
23
- * site MUST build the key through this one helper).
23
+ * Build the canonical `workflow_runs.workflow_ref` for an AKM workflow asset.
24
24
  */
25
- export function canonicalWorkflowRunRef(origin, canonicalName) {
26
- return `${origin ? `${origin}//` : ""}workflows/${canonicalName}`;
25
+ export function canonicalWorkflowRunRef(bundle, canonicalName) {
26
+ return makeBundleRef(bundle, `workflows/${canonicalName}`);
27
27
  }
28
- /** Parse a workflow ref using the canonical `[bundle//]workflows/<name>` grammar. */
28
+ /** Parse a workflow ref using the canonical `[bundle//]conceptId` grammar. */
29
29
  export function parseWorkflowRefInput(ref) {
30
- return parseRefInput(ref.trim());
30
+ const parsed = parseBundleRef(ref.trim());
31
+ if (parsed.fragment !== undefined) {
32
+ throw new UsageError(`Export fragment "#${parsed.fragment}" is not accepted in a workflow ref.`, "INVALID_FLAG_VALUE");
33
+ }
34
+ if (parsed.conceptId.startsWith("workflow:")) {
35
+ throw new UsageError(`Invalid workflow ref "${ref.trim()}". Use [bundle//]conceptId, such as workflows/release.`, "INVALID_FLAG_VALUE");
36
+ }
37
+ return parsed;
38
+ }
39
+ /** Resolve input sugar to the workflow's canonical run identity. */
40
+ export async function canonicalizeWorkflowRefInput(ref) {
41
+ return (await loadWorkflowAsset(ref)).ref;
31
42
  }
32
43
  /**
33
44
  * Resolve a workflow ref to a fully-projected {@link WorkflowAsset}. Prefers the
@@ -35,55 +46,198 @@ export function parseWorkflowRefInput(ref) {
35
46
  * parsing the source file from disk.
36
47
  */
37
48
  export async function loadWorkflowAsset(ref) {
38
- const parsed = parseWorkflowRefInput(ref);
39
- if (parsed.type !== "workflow") {
40
- throw new UsageError(`Expected a workflow ref (workflows/<name>), got "${ref}".`);
41
- }
49
+ const bundleRef = parseWorkflowRefInput(ref);
42
50
  const config = loadConfig();
43
51
  const allSources = resolveSourceEntries(undefined, config);
44
- const searchSources = resolveSourcesForOrigin(parsed.origin, allSources);
52
+ const installations = deriveInstallations(allSources);
53
+ const searchSources = allSources.flatMap((source, index) => {
54
+ const bundleId = installations[index]?.id;
55
+ if (!bundleId || (bundleRef.bundle !== undefined && bundleRef.bundle !== bundleId))
56
+ return [];
57
+ return [{ source, bundleId }];
58
+ });
59
+ if (bundleRef.bundle && searchSources.length === 0) {
60
+ throw new UsageError(`Bundle "${bundleRef.bundle}" was not found among configured sources.`, "INVALID_FLAG_VALUE");
61
+ }
45
62
  let assetPath;
46
63
  let sourcePath;
47
- for (const source of searchSources) {
64
+ let sourceBundleId;
65
+ let workflowName;
66
+ let workflowAdapterId;
67
+ let rejectedSource;
68
+ for (const candidateSource of searchSources) {
69
+ const { source, bundleId } = candidateSource;
48
70
  try {
49
- assetPath = await resolveAssetPath(source.path, "workflow", parsed.name);
71
+ const adapterId = source.adapterId ?? detectAdapterId(source.path);
72
+ const candidateName = adapterId === "akm-workflow" ? bundleRef.conceptId : workflowNameFromConceptId(bundleRef.conceptId);
73
+ const ownedSource = source.adapterId ? source : { ...source, adapterId };
74
+ if (!candidateName) {
75
+ if (adapterOwnsConcept(source.path, adapterId, bundleRef.conceptId)) {
76
+ rejectedSource ??= { source: ownedSource, bundleId };
77
+ break;
78
+ }
79
+ continue;
80
+ }
81
+ const candidate = await resolveNativeWorkflowPath(source.path, adapterId, candidateName);
82
+ if (!ownsNativeWorkflowRuntime(ownedSource)) {
83
+ rejectedSource ??= { source: ownedSource, bundleId };
84
+ break;
85
+ }
86
+ assetPath = candidate;
50
87
  sourcePath = source.path;
88
+ sourceBundleId = bundleId;
89
+ workflowName = candidateName;
90
+ workflowAdapterId = adapterId;
51
91
  break;
52
92
  }
53
- catch {
54
- /* continue */
93
+ catch (error) {
94
+ if (error instanceof NotFoundError)
95
+ continue;
96
+ throw error;
55
97
  }
56
98
  }
57
99
  if (!assetPath) {
58
- throw new NotFoundError(`Workflow not found for ref: workflows/${parsed.name}`);
59
- }
60
- const resolvedSourcePath = sourcePath ?? resolveStashDir() ?? assetPath;
61
- // Canonicalize the stored ref: `workflows/foo.yaml` and `workflows/foo`
62
- // resolve to the same file, so they MUST share one run identity. The raw
63
- // `parsed.name` (with any extension) is what drives file resolution above;
64
- // only the persisted/queried ref is collapsed (matches the index entry key,
65
- // which is keyed by the extension-stripped canonical name).
66
- const canonicalName = canonicalizeWorkflowName(parsed.name);
67
- const fullRef = canonicalWorkflowRunRef(parsed.origin, canonicalName);
68
- // Format detection by extension: `.yaml`/`.yml` is a YAML workflow program
69
- // (redesign addendum, R1); everything else is the markdown document format.
70
- if (isWorkflowProgramPath(assetPath)) {
71
- const program = loadWorkflowProgramFromDisk(assetPath);
72
- return projectProgramAsset(program, fullRef, assetPath, resolvedSourcePath);
73
- }
74
- const cached = readWorkflowDocumentFromIndex(resolvedSourcePath, fullRef);
100
+ if (rejectedSource) {
101
+ const sourceName = rejectedSource.bundleId;
102
+ const adapterId = rejectedSource.source.adapterId ?? "unassigned";
103
+ throw new UsageError(`Bundle "${sourceName}" uses adapter "${adapterId}", which does not support native workflow execution.`, "INVALID_FLAG_VALUE");
104
+ }
105
+ throw new NotFoundError(`Workflow not found for ref: ${ref}`);
106
+ }
107
+ const resolvedSourcePath = sourcePath;
108
+ // Canonicalize the stored ref: `workflows/foo.md` and `workflows/foo` resolve
109
+ // to the same file, so they MUST share one run identity.
110
+ const canonicalName = canonicalizeWorkflowName(workflowName);
111
+ const fullRef = workflowAdapterId === "akm-workflow"
112
+ ? makeBundleRef(sourceBundleId, canonicalName)
113
+ : canonicalWorkflowRunRef(sourceBundleId, canonicalName);
114
+ const cached = readWorkflowDocumentFromIndex(resolvedSourcePath, fullRef, workflowAdapterId);
75
115
  const document = cached ?? loadWorkflowDocumentFromDisk(assetPath);
76
- return projectAsset(document, fullRef, assetPath, resolvedSourcePath);
116
+ return projectAsset(document, fullRef, assetPath, resolvedSourcePath, workflowAdapterId, canonicalName);
117
+ }
118
+ function ownsNativeWorkflowRuntime(source) {
119
+ return source.adapterId === "akm" || source.adapterId === "akm-workflow";
120
+ }
121
+ function workflowNameFromConceptId(conceptId) {
122
+ const prefix = "workflows/";
123
+ return conceptId.startsWith(prefix) && conceptId.length > prefix.length ? conceptId.slice(prefix.length) : undefined;
124
+ }
125
+ function adapterOwnsConcept(sourcePath, adapterId, conceptId) {
126
+ const adapter = adapterForId(adapterId);
127
+ if (!adapter)
128
+ return false;
129
+ const normalized = conceptId.replaceAll("\\", "/");
130
+ if (!normalized ||
131
+ path.posix.isAbsolute(normalized) ||
132
+ normalized === ".." ||
133
+ normalized.startsWith("../") ||
134
+ path.posix.normalize(normalized) !== normalized) {
135
+ return false;
136
+ }
137
+ const extensions = [...adapter.extensions].sort((left, right) => right.length - left.length);
138
+ const extension = extensions.find((candidate) => normalized.toLowerCase().endsWith(candidate.toLowerCase()));
139
+ const extensionless = extension ? normalized.slice(0, -extension.length) : normalized;
140
+ const parent = path.join(sourcePath, path.posix.dirname(extensionless));
141
+ let realRoot;
142
+ let realParent;
143
+ try {
144
+ realRoot = fs.realpathSync(sourcePath);
145
+ realParent = fs.realpathSync(parent);
146
+ }
147
+ catch {
148
+ return false;
149
+ }
150
+ if (!isWithin(realParent, realRoot))
151
+ return false;
152
+ const basename = path.posix.basename(extensionless);
153
+ let entries;
154
+ try {
155
+ entries = fs.readdirSync(realParent, { withFileTypes: true });
156
+ }
157
+ catch {
158
+ return false;
159
+ }
160
+ for (const entry of entries) {
161
+ if (!entry.isFile())
162
+ continue;
163
+ const recognizedExtension = extensions.find((candidate) => entry.name.toLowerCase().endsWith(candidate.toLowerCase()) &&
164
+ entry.name.slice(0, -candidate.length) === basename);
165
+ if (!recognizedExtension)
166
+ continue;
167
+ const candidatePath = path.join(realParent, entry.name);
168
+ try {
169
+ const document = adapter.recognize({ id: adapterId, adapter: adapterId, root: realRoot, writable: false }, buildFileContext(realRoot, candidatePath));
170
+ if (document)
171
+ return true;
172
+ }
173
+ catch {
174
+ // A malformed matching file still belongs to the earlier adapter and cannot be bypassed for execution.
175
+ return true;
176
+ }
177
+ }
178
+ return false;
179
+ }
180
+ async function resolveNativeWorkflowPath(sourcePath, adapterId, name) {
181
+ if (adapterId !== "akm-workflow")
182
+ return resolveAssetPath(sourcePath, "workflow", name);
183
+ const canonicalName = canonicalizeWorkflowName(name);
184
+ let realRoot;
185
+ try {
186
+ realRoot = fs.realpathSync(sourcePath);
187
+ }
188
+ catch {
189
+ throw new NotFoundError(`Workflow bundle root not found: ${sourcePath}`);
190
+ }
191
+ const parent = path.join(sourcePath, path.dirname(canonicalName));
192
+ if (!isWithin(parent, realRoot)) {
193
+ throw new UsageError("Workflow ref resolves outside the bundle root.", "PATH_ESCAPE_VIOLATION");
194
+ }
195
+ let entries;
196
+ try {
197
+ entries = fs.readdirSync(parent, { withFileTypes: true });
198
+ }
199
+ catch {
200
+ throw new NotFoundError(`Workflow not found: ${name}`);
201
+ }
202
+ const basename = path.basename(canonicalName);
203
+ for (const extension of WORKFLOW_EXTENSIONS) {
204
+ const matches = entries.filter((entry) => {
205
+ if (!entry.isFile() && !entry.isSymbolicLink())
206
+ return false;
207
+ const entryExtension = path.extname(entry.name);
208
+ return entryExtension.toLowerCase() === extension && entry.name.slice(0, -entryExtension.length) === basename;
209
+ });
210
+ if (matches.length > 1) {
211
+ throw new UsageError(`Workflow "${canonicalName}" has multiple ${extension} files that differ only by extension case.`, "RESOURCE_ALREADY_EXISTS");
212
+ }
213
+ const match = matches[0];
214
+ if (!match)
215
+ continue;
216
+ const candidate = path.join(parent, match.name);
217
+ let realTarget;
218
+ try {
219
+ if (!fs.statSync(candidate).isFile())
220
+ continue;
221
+ realTarget = fs.realpathSync(candidate);
222
+ }
223
+ catch {
224
+ continue;
225
+ }
226
+ if (!isWithin(realTarget, realRoot)) {
227
+ throw new UsageError("Workflow ref resolves outside the bundle root.", "PATH_ESCAPE_VIOLATION");
228
+ }
229
+ return realTarget;
230
+ }
231
+ throw new NotFoundError(`Workflow not found: ${name}`);
77
232
  }
78
233
  /**
79
234
  * Resolve the `entries.id` for an indexed workflow, or null when the index
80
235
  * database does not yet exist or has no matching entry.
81
236
  */
82
- export function resolveWorkflowEntryId(sourcePath, ref) {
237
+ export function resolveWorkflowEntryId(sourcePath, ref, adapterId) {
83
238
  if (!fs.existsSync(getDbPath()))
84
239
  return null;
85
- const parsed = parseWorkflowRefInput(ref);
86
- const entryKey = `${sourcePath}:${parsed.type}:${parsed.name}`;
240
+ const entryKey = workflowEntryKey(sourcePath, ref, adapterId);
87
241
  return withIndexDb((db) => {
88
242
  const row = db
89
243
  .prepare(`SELECT id
@@ -95,14 +249,6 @@ export function resolveWorkflowEntryId(sourcePath, ref) {
95
249
  return row?.id ?? null;
96
250
  });
97
251
  }
98
- function loadWorkflowProgramFromDisk(assetPath) {
99
- const content = fs.readFileSync(assetPath, "utf8");
100
- const result = parseWorkflowProgram(content, { path: assetPath });
101
- if (!result.ok) {
102
- throw new UsageError(formatWorkflowErrors(assetPath, result.errors));
103
- }
104
- return result.program;
105
- }
106
252
  function loadWorkflowDocumentFromDisk(assetPath) {
107
253
  const content = fs.readFileSync(assetPath, "utf8");
108
254
  const result = parseWorkflow(content, { path: assetPath });
@@ -111,20 +257,19 @@ function loadWorkflowDocumentFromDisk(assetPath) {
111
257
  }
112
258
  return result.document;
113
259
  }
114
- function readWorkflowDocumentFromIndex(sourcePath, ref) {
260
+ function readWorkflowDocumentFromIndex(sourcePath, ref, adapterId) {
115
261
  if (!fs.existsSync(getDbPath()))
116
262
  return null;
117
- const parsed = parseWorkflowRefInput(ref);
118
- const entryKey = `${sourcePath}:${parsed.type}:${parsed.name}`;
263
+ const entryKey = workflowEntryKey(sourcePath, ref, adapterId);
119
264
  return withIndexDb((db) => {
120
265
  const row = db
121
- .prepare(`SELECT wd.document_json AS document_json
266
+ .prepare(`SELECT wd.document_json AS document_json, wd.schema_version AS schema_version
122
267
  FROM workflow_documents wd
123
268
  JOIN entries e ON e.id = wd.entry_id
124
269
  WHERE e.entry_type = 'workflow' AND e.entry_key = ?
125
270
  LIMIT 1`)
126
271
  .get(entryKey);
127
- if (!row)
272
+ if (!row || row.schema_version !== WORKFLOW_SCHEMA_VERSION)
128
273
  return null;
129
274
  try {
130
275
  return JSON.parse(row.document_json);
@@ -134,44 +279,48 @@ function readWorkflowDocumentFromIndex(sourcePath, ref) {
134
279
  }
135
280
  });
136
281
  }
137
- function projectAsset(doc, ref, assetPath, sourcePath) {
282
+ function workflowEntryKey(sourcePath, ref, adapterId) {
283
+ const bundleRef = parseBundleRef(ref);
284
+ if ((adapterId ?? detectAdapterId(sourcePath)) === "akm-workflow") {
285
+ return `${sourcePath}:concept:${bundleRef.conceptId}`;
286
+ }
287
+ const name = workflowNameFromConceptId(bundleRef.conceptId);
288
+ if (!name)
289
+ throw new UsageError(`Expected a workflow ref, got "${ref}".`);
290
+ return `${sourcePath}:workflow:${name}`;
291
+ }
292
+ function projectAsset(doc, ref, assetPath, sourcePath, adapterId, canonicalName) {
293
+ const title = canonicalName.split("/").pop() || canonicalName;
138
294
  return {
139
295
  ref,
140
296
  path: assetPath,
141
297
  sourcePath,
142
- title: doc.title,
143
- ...(doc.parameters
298
+ adapterId,
299
+ title,
300
+ ...(doc.params
144
301
  ? {
145
- parameters: doc.parameters.map((p) => ({
146
- name: p.name,
147
- ...(p.description ? { description: p.description } : {}),
148
- })),
302
+ parameters: Object.entries(doc.params).map(([name, schema]) => {
303
+ const description = schema.description;
304
+ return { name, ...(typeof description === "string" && description ? { description } : {}) };
305
+ }),
149
306
  }
150
307
  : {}),
151
308
  steps: doc.steps.map((s) => ({
152
309
  id: s.id,
153
- title: s.title,
154
- instructions: s.instructions.text,
155
- ...(s.completionCriteria ? { completionCriteria: s.completionCriteria.map((c) => c.text) } : {}),
310
+ title: s.id,
311
+ instructions: s.instructions?.text ?? stepFallbackInstructions(s),
312
+ ...(s.gateRubric?.text.trim() ? { completionCriteria: [s.gateRubric.text] } : {}),
156
313
  sequenceIndex: s.sequenceIndex,
157
314
  })),
158
315
  document: doc,
159
316
  };
160
317
  }
161
- /**
162
- * Project a parsed YAML program into the run-repository asset shape. Step
163
- * instructions carry the RAW `${{ … }}` templates — resolution happens in
164
- * the engine against the frozen plan, never here.
165
- */
166
- function projectProgramAsset(program, ref, assetPath, sourcePath) {
167
- const parameters = projectProgramParameters(program);
168
- return {
169
- ref,
170
- path: assetPath,
171
- sourcePath,
172
- title: program.name,
173
- ...(parameters ? { parameters } : {}),
174
- steps: projectProgramStepDefinitions(program),
175
- program,
176
- };
318
+ /** A route-only step with no body section still needs a non-empty spine instructions string. */
319
+ function stepFallbackInstructions(step) {
320
+ if (!step.route)
321
+ return "";
322
+ const branches = step.route.branches.map((b) => `"${b.match}" -> ${b.stepId}`);
323
+ if (step.route.defaultStepId !== undefined)
324
+ branches.push(`default -> ${step.route.defaultStepId}`);
325
+ return `Route on ${step.route.input}: ${branches.join(", ")}.`;
177
326
  }
@@ -1,14 +1,4 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * Validated JSON shape for a workflow asset.
6
- *
7
- * `parseWorkflow` (parser.ts) converts a workflow markdown file into a
8
- * `WorkflowDocument` plus a list of `WorkflowError`s. The document is the
9
- * single source of truth consumed by the renderer, the indexer (cached
10
- * into `workflow_documents` in `index.db`), and the run engine. Source
11
- * markdown is referenced by `SourceRef` line spans so editors and agents
12
- * can rewrite content in place without a full re-parse.
13
- */
14
- export const WORKFLOW_SCHEMA_VERSION = 1;
4
+ export const WORKFLOW_SCHEMA_VERSION = 2;
@@ -9,18 +9,14 @@
9
9
  * demonstrates each criterion is met, and returns either a pass or structured
10
10
  * corrective feedback steering the agent on what to finish/fix.
11
11
  *
12
- * The LLM call is injected (`judge`) so the gate is unit-testable without a
13
- * live endpoint, and the whole gate is fail-open: when no criteria exist or no
14
- * judge is available the step completes as before (per the workflow-agent
15
- * check-in ADR).
12
+ * The judge call is injected so the gate is unit-testable without a live
13
+ * endpoint. A declared gate is fail-closed: only a well-formed affirmative
14
+ * verdict advances the step.
16
15
  *
17
16
  * @module workflows/validate-summary
18
17
  */
19
18
  import validateSummaryJudgePrompt from "../assets/prompts/validate-summary-judge.md" with { type: "text" };
20
19
  import { parseJsonResponse } from "../core/parse.js";
21
- /** Feedback surfaced when a REQUIRED gate's judge could not be evaluated. */
22
- const REQUIRED_GATE_JUDGE_UNAVAILABLE_FEEDBACK = "The required completion gate could not be judged — the LLM threw, was unreachable, or returned an " +
23
- "unparseable verdict. A required gate must be judged; refusing to pass it. Restore the judge and re-evaluate.";
24
20
  const JUDGE_SYSTEM = validateSummaryJudgePrompt;
25
21
  function buildUserPrompt(input) {
26
22
  const criteria = input.completionCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n");
@@ -39,50 +35,45 @@ function buildUserPrompt(input) {
39
35
  /**
40
36
  * Run the summary-validation gate.
41
37
  *
42
- * Fail-open contract (NON-required gates):
43
- * - no criteria → `{ complete: true, skipped: true }`
44
- * - no judge → `{ complete: true, skipped: true }`
45
- * - judge throws / returns unparseable → `{ complete: true, skipped: true }`
46
- *
47
- * REQUIRED gates (`opts.required`) do NOT fail open on an un-evaluable judge
48
- * (Codex round-3 finding A): a judge that throws / is unreachable, or returns an
49
- * unparseable / malformed verdict, yields `{ complete: false, errored: true }`
50
- * so the caller BLOCKS the step rather than silently passing an unjudged gate.
51
- * (A required gate with NO judge at all is blocked upstream in
52
- * `finalizeExecutedStep` before this gate runs, so that branch stays fail-open.)
53
- *
54
- * Only a well-formed `complete: false` verdict blocks completion.
38
+ * No criteria skips verification. A missing, failing, or malformed judge is a
39
+ * rejection: declared criteria are never silently bypassed.
55
40
  */
56
- export async function validateStepSummary(input, judge, opts) {
57
- const required = opts?.required === true;
41
+ export async function validateStepSummary(input, judge, signal) {
58
42
  const criteria = input.completionCriteria.filter((c) => c.trim().length > 0);
59
43
  if (criteria.length === 0) {
60
44
  return { complete: true, missing: [], skipped: true };
61
45
  }
62
46
  if (!judge) {
63
- return { complete: true, missing: [], skipped: true };
47
+ return {
48
+ complete: false,
49
+ missing: criteria,
50
+ feedback: "This step declares completion criteria but no verification judge is available.",
51
+ };
64
52
  }
65
53
  let raw;
66
54
  try {
55
+ if (signal?.aborted)
56
+ throw interruptionReason(signal);
67
57
  raw = await judge({ system: JUDGE_SYSTEM, user: buildUserPrompt({ ...input, completionCriteria: criteria }) });
58
+ if (signal?.aborted)
59
+ throw interruptionReason(signal);
68
60
  }
69
61
  catch {
70
- // LLM unreachable / errored. A REQUIRED gate must be judged — block rather
71
- // than pass an unjudged gate; a non-required gate fails open so offline use
72
- // keeps working.
73
- if (required) {
74
- return { complete: false, missing: [], errored: true, feedback: REQUIRED_GATE_JUDGE_UNAVAILABLE_FEEDBACK };
75
- }
76
- return { complete: true, missing: [], skipped: true };
62
+ if (signal?.aborted)
63
+ throw interruptionReason(signal);
64
+ return {
65
+ complete: false,
66
+ missing: criteria,
67
+ feedback: "The verification judge failed. Retry after fixing the verifier configuration or service.",
68
+ };
77
69
  }
78
70
  const parsed = parseJsonResponse(raw);
79
71
  if (!parsed || typeof parsed.complete !== "boolean") {
80
- // An unparseable / malformed verdict is a judge that did not actually judge:
81
- // a required gate blocks; a non-required gate fails open.
82
- if (required) {
83
- return { complete: false, missing: [], errored: true, feedback: REQUIRED_GATE_JUDGE_UNAVAILABLE_FEEDBACK };
84
- }
85
- return { complete: true, missing: [], skipped: true };
72
+ return {
73
+ complete: false,
74
+ missing: criteria,
75
+ feedback: "The verification judge returned a malformed verdict instead of the required JSON result.",
76
+ };
86
77
  }
87
78
  if (parsed.complete) {
88
79
  return { complete: true, missing: [] };
@@ -96,3 +87,6 @@ export async function validateStepSummary(input, judge, opts) {
96
87
  "Finish the outstanding work and resubmit with a summary that addresses each criterion.";
97
88
  return { complete: false, missing, feedback };
98
89
  }
90
+ function interruptionReason(signal) {
91
+ return signal.reason instanceof Error ? signal.reason : new Error("Workflow verification interrupted.");
92
+ }