akm-cli 0.9.16 → 0.9.17-alpha.10

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 (403) hide show
  1. package/CHANGELOG.md +2101 -0
  2. package/STABILITY.md +11 -10
  3. package/dist/akm +124 -193
  4. package/dist/akm-migrate +38 -19
  5. package/dist/assets/hints/cli-hints-full.md +6 -7
  6. package/dist/assets/improve-strategies/catchup.json +0 -3
  7. package/dist/assets/improve-strategies/consolidate.json +0 -1
  8. package/dist/assets/improve-strategies/default.json +1 -2
  9. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
  10. package/dist/assets/improve-strategies/quick.json +1 -2
  11. package/dist/assets/improve-strategies/reflect-distill.json +1 -2
  12. package/dist/assets/improve-strategies/thorough.json +0 -3
  13. package/dist/assets/prompts/consolidate-pair.md +20 -0
  14. package/dist/assets/prompts/consolidate-system.md +4 -11
  15. package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
  17. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
  18. package/dist/assets/templates/html/health.html +3 -5
  19. package/dist/cli/retired-commands.js +1 -1
  20. package/dist/cli/shared.js +6 -2
  21. package/dist/cli/unknown-flags.js +24 -1
  22. package/dist/cli.js +68 -10
  23. package/dist/commands/agent/agent-dispatch.js +1 -1
  24. package/dist/commands/command/command-execution.js +24 -62
  25. package/dist/commands/feedback-cli.js +0 -1
  26. package/dist/commands/health/accept-rate.js +6 -0
  27. package/dist/commands/health/archive-usage.js +92 -0
  28. package/dist/commands/health/checks.js +83 -74
  29. package/dist/commands/health/config-skew.js +38 -0
  30. package/dist/commands/health/data-dir-usage.js +25 -13
  31. package/dist/commands/health/egress.js +54 -0
  32. package/dist/commands/health/html-report.js +1 -42
  33. package/dist/commands/health/improve-metrics.js +136 -591
  34. package/dist/commands/health/md-report.js +1 -6
  35. package/dist/commands/health/plugin-staleness.js +53 -3
  36. package/dist/commands/health/renderers.js +12 -4
  37. package/dist/commands/health/report-view-model.js +14 -120
  38. package/dist/commands/health/types-improve.js +4 -19
  39. package/dist/commands/health/windows.js +64 -74
  40. package/dist/commands/health.js +145 -143
  41. package/dist/commands/improve/consolidate/chunking.js +26 -117
  42. package/dist/commands/improve/consolidate/continuity-check.js +137 -0
  43. package/dist/commands/improve/consolidate/pair-pass.js +791 -0
  44. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  45. package/dist/commands/improve/consolidate.js +589 -1127
  46. package/dist/commands/improve/content-hash.js +16 -24
  47. package/dist/commands/improve/distill/content-repair.js +18 -100
  48. package/dist/commands/improve/distill-guards.js +20 -81
  49. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  50. package/dist/commands/improve/distill.js +608 -1041
  51. package/dist/commands/improve/eligibility.js +126 -390
  52. package/dist/commands/improve/execution.js +8 -10
  53. package/dist/commands/improve/extract-prompt.js +1 -2
  54. package/dist/commands/improve/extract.js +487 -1046
  55. package/dist/commands/improve/feedback-valence.js +0 -25
  56. package/dist/commands/improve/improve-cli.js +75 -169
  57. package/dist/commands/improve/improve-result-file.js +10 -66
  58. package/dist/commands/improve/improve-strategies.js +52 -4
  59. package/dist/commands/improve/improve-usage-report.js +18 -64
  60. package/dist/commands/improve/improve.js +480 -1074
  61. package/dist/commands/improve/ledger.js +119 -0
  62. package/dist/commands/improve/locks.js +2 -8
  63. package/dist/commands/improve/loop-stages.js +415 -1073
  64. package/dist/commands/improve/memory/derived-ref.js +12 -77
  65. package/dist/commands/improve/memory/memory-belief.js +16 -118
  66. package/dist/commands/improve/memory/memory-improve.js +266 -14
  67. package/dist/commands/improve/outcome-loop.js +28 -156
  68. package/dist/commands/improve/planner.js +5 -15
  69. package/dist/commands/improve/preparation.js +779 -2319
  70. package/dist/commands/improve/proactive-maintenance.js +34 -101
  71. package/dist/commands/improve/reflect-noise.js +104 -280
  72. package/dist/commands/improve/reflect.js +642 -1353
  73. package/dist/commands/improve/retrieval-gate.js +127 -0
  74. package/dist/commands/improve/retrieval-scope.js +92 -0
  75. package/dist/commands/improve/salience.js +41 -240
  76. package/dist/commands/improve/session-asset.js +19 -100
  77. package/dist/commands/improve/stage.js +322 -0
  78. package/dist/commands/lint/base-linter.js +37 -15
  79. package/dist/commands/proposal/drain.js +261 -578
  80. package/dist/commands/proposal/proposal-cli.js +19 -20
  81. package/dist/commands/proposal/proposal-types.js +31 -24
  82. package/dist/commands/proposal/proposal.js +38 -8
  83. package/dist/commands/proposal/propose.js +134 -160
  84. package/dist/commands/proposal/repository.js +1097 -1394
  85. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  86. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  87. package/dist/commands/proposal/validators/proposals.js +22 -89
  88. package/dist/commands/read/curate.js +105 -462
  89. package/dist/commands/read/knowledge.js +3 -2
  90. package/dist/commands/read/search-cli.js +16 -33
  91. package/dist/commands/read/search.js +17 -23
  92. package/dist/commands/read/show.js +57 -108
  93. package/dist/commands/sources/bundle-cli.js +25 -2
  94. package/dist/commands/sources/bundle-config-ops.js +4 -0
  95. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  96. package/dist/commands/sources/info.js +127 -29
  97. package/dist/commands/sources/installed-stashes.js +197 -746
  98. package/dist/commands/sources/schema-repair.js +98 -129
  99. package/dist/commands/sources/source-add.js +62 -12
  100. package/dist/commands/sources/source-manage.js +9 -2
  101. package/dist/commands/sources/stash-cli.js +24 -4
  102. package/dist/commands/tasks/explain.js +10 -13
  103. package/dist/commands/tasks/tasks-cli.js +12 -13
  104. package/dist/commands/tasks/tasks.js +350 -936
  105. package/dist/commands/tasks/validate.js +26 -24
  106. package/dist/commands/workflow/plan.js +22 -29
  107. package/dist/commands/workflow-cli.js +4 -4
  108. package/dist/core/adapter/adapters/akm-adapter.js +2 -1
  109. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  110. package/dist/core/adapter/adapters/akm-metadata.js +42 -12
  111. package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
  112. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  113. package/dist/core/adapter/execution-source.js +17 -29
  114. package/dist/core/asset/asset-placement.js +4 -13
  115. package/dist/core/asset/frontmatter.js +106 -1
  116. package/dist/core/asset/resolve-ref.js +1 -1
  117. package/dist/core/bundle-id.js +42 -5
  118. package/dist/core/bundle-rename.js +285 -0
  119. package/dist/core/config/config-io.js +1 -2
  120. package/dist/core/config/config-schema.js +9 -34
  121. package/dist/core/config/config-walker.js +1 -1
  122. package/dist/core/config/config.js +184 -111
  123. package/dist/core/config/engine-semantics.js +0 -2
  124. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  125. package/dist/core/config/schema/embedding.js +20 -5
  126. package/dist/core/config/schema/engines.js +5 -0
  127. package/dist/core/config/schema/execution.js +1 -1
  128. package/dist/core/config/schema/experimental.js +1 -1
  129. package/dist/core/config/schema/improve-processes.js +54 -125
  130. package/dist/core/config/schema/improve.js +4 -42
  131. package/dist/core/config/schema/index-config.js +9 -48
  132. package/dist/core/config/schema/scheduler.js +12 -12
  133. package/dist/core/config/schema/search.js +6 -22
  134. package/dist/core/env-secret-ref.js +0 -1
  135. package/dist/core/errors.js +8 -9
  136. package/dist/core/file-change.js +13 -5
  137. package/dist/core/file-lock.js +76 -173
  138. package/dist/core/improve-result.js +35 -7
  139. package/dist/core/improve-types.js +0 -1
  140. package/dist/core/logs-db.js +2 -2
  141. package/dist/core/loopback.js +7 -12
  142. package/dist/core/non-task-input.js +20 -0
  143. package/dist/core/parse.js +13 -16
  144. package/dist/core/paths.js +0 -24
  145. package/dist/core/redaction.js +109 -2
  146. package/dist/core/run-lock.js +2 -5
  147. package/dist/core/spawn-env.js +1 -1
  148. package/dist/core/state/migrations.js +123 -61
  149. package/dist/core/state-db-scope.js +2 -4
  150. package/dist/core/state-db.js +126 -692
  151. package/dist/core/time.js +0 -20
  152. package/dist/core/type-presentation.js +1 -9
  153. package/dist/core/write-source.js +294 -1005
  154. package/dist/execution/input-contract.js +1 -1
  155. package/dist/execution/resolved-request.js +135 -689
  156. package/dist/execution/source.js +63 -257
  157. package/dist/execution/target-ref.js +1 -1
  158. package/dist/indexer/bundle-identity-guard.js +2 -2
  159. package/dist/indexer/db/llm-cache.js +2 -2
  160. package/dist/indexer/ensure-index.js +77 -73
  161. package/dist/indexer/index-rebuild-lock.js +3 -11
  162. package/dist/indexer/index-writer-lock.js +8 -17
  163. package/dist/indexer/index-written-assets.js +141 -154
  164. package/dist/indexer/indexer.js +400 -1124
  165. package/dist/indexer/links/declared-links.js +90 -0
  166. package/dist/indexer/materialize-embeddings.js +60 -397
  167. package/dist/indexer/passes/memory-inference.js +96 -90
  168. package/dist/indexer/passes/metadata.js +132 -219
  169. package/dist/indexer/read-preflight.js +0 -7
  170. package/dist/indexer/scan/doc-to-entry.js +2 -3
  171. package/dist/indexer/scan/drain-dir.js +1 -1
  172. package/dist/indexer/search/db-search.js +190 -590
  173. package/dist/indexer/search/fts-query.js +30 -41
  174. package/dist/indexer/search/ranking.js +28 -154
  175. package/dist/indexer/search/search-attribution.js +12 -32
  176. package/dist/indexer/search/search-fields.js +11 -15
  177. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  178. package/dist/indexer/search/search-source.js +1 -4
  179. package/dist/indexer/usage/usage-events.js +36 -7
  180. package/dist/indexer/walk/walker.js +3 -4
  181. package/dist/integrations/agent/engine-fallback.js +23 -40
  182. package/dist/integrations/agent/engine-resolution.js +93 -183
  183. package/dist/integrations/agent/execution.js +507 -0
  184. package/dist/integrations/agent/model-map.js +28 -156
  185. package/dist/integrations/agent/request-lowering.js +66 -141
  186. package/dist/integrations/agent/runner-dispatch.js +143 -321
  187. package/dist/integrations/agent/runner.js +54 -14
  188. package/dist/integrations/lockfile.js +53 -101
  189. package/dist/llm/client.js +18 -6
  190. package/dist/llm/embedders/deterministic.js +2 -3
  191. package/dist/llm/embedders/profile.js +71 -0
  192. package/dist/llm/embedders/remote.js +11 -17
  193. package/dist/llm/feature-gate.js +0 -8
  194. package/dist/llm/index-passes.js +3 -5
  195. package/dist/llm/memory-infer.js +1 -2
  196. package/dist/llm/structured-call.js +5 -24
  197. package/dist/output/generic-render.js +23 -11
  198. package/dist/output/html-render.js +13 -10
  199. package/dist/output/render-registry.js +3 -32
  200. package/dist/output/shapes/helpers.js +25 -38
  201. package/dist/output/shapes/passthrough.js +1 -9
  202. package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
  203. package/dist/output/text/command-format.js +69 -31
  204. package/dist/output/text/helpers.js +1 -1
  205. package/dist/output/text/migrate.js +5 -14
  206. package/dist/output/text/proposal-format.js +48 -3
  207. package/dist/output/text/show-format.js +13 -17
  208. package/dist/output/text/workflow-format.js +0 -32
  209. package/dist/output/text.js +2 -0
  210. package/dist/registry/factory.js +4 -19
  211. package/dist/registry/network.js +66 -220
  212. package/dist/registry/providers/index.js +0 -2
  213. package/dist/registry/providers/skills-sh.js +3 -14
  214. package/dist/registry/providers/static-index.js +24 -26
  215. package/dist/registry/resolve.js +55 -131
  216. package/dist/scripts/akm-migrate-node.js +42948 -92369
  217. package/dist/scripts/akm-migrate.js +42935 -92354
  218. package/dist/setup/registry-stash-loader.js +4 -13
  219. package/dist/setup/semantic-assets.js +3 -44
  220. package/dist/setup/setup.js +1 -1
  221. package/dist/setup/steps/connection.js +5 -6
  222. package/dist/setup/steps/platforms.js +2 -2
  223. package/dist/setup/steps/tasks.js +25 -15
  224. package/dist/sources/provider-factory.js +17 -18
  225. package/dist/sources/providers/filesystem.js +2 -3
  226. package/dist/sources/providers/git-install.js +7 -1
  227. package/dist/sources/providers/git-provider.js +0 -3
  228. package/dist/sources/providers/git-stash.js +83 -21
  229. package/dist/sources/providers/npm.js +2 -4
  230. package/dist/sources/providers/provider-utils.js +5 -10
  231. package/dist/sources/providers/website.js +0 -2
  232. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  233. package/dist/sources/website-url.js +2 -2
  234. package/dist/storage/database.js +9 -35
  235. package/dist/storage/repositories/improve-ledger-repository.js +209 -0
  236. package/dist/storage/repositories/index-connection.js +39 -72
  237. package/dist/storage/repositories/index-entries-repository.js +131 -129
  238. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  239. package/dist/storage/repositories/index-entry-schema.js +101 -268
  240. package/dist/storage/repositories/index-fts-repository.js +86 -256
  241. package/dist/storage/repositories/index-links-repository.js +143 -0
  242. package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
  243. package/dist/storage/repositories/index-meta-repository.js +6 -4
  244. package/dist/storage/repositories/index-schema.js +257 -325
  245. package/dist/storage/repositories/index-utility-repository.js +8 -29
  246. package/dist/storage/repositories/index-vec-repository.js +133 -414
  247. package/dist/storage/repositories/outcome-repository.js +2 -1
  248. package/dist/storage/repositories/proposals-repository.js +104 -1
  249. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  250. package/dist/storage/repositories/salience-repository.js +1 -19
  251. package/dist/storage/repositories/task-history-repository.js +26 -4
  252. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  253. package/dist/storage/sqlite-migrations.js +136 -0
  254. package/dist/storage/sqlite-pragmas.js +11 -9
  255. package/dist/storage/sqlite-transaction.js +170 -0
  256. package/dist/storage/state-db-integrity.js +130 -0
  257. package/dist/tasks/activation-config.js +134 -62
  258. package/dist/tasks/backends/cron.js +191 -302
  259. package/dist/tasks/backends/exec-utils.js +2 -5
  260. package/dist/tasks/backends/launchd.js +141 -748
  261. package/dist/tasks/backends/schtasks.js +119 -623
  262. package/dist/tasks/prepare/prepare-support.js +5 -15
  263. package/dist/tasks/prepare/prepare.js +0 -2
  264. package/dist/tasks/resolve-akm-bin.js +20 -79
  265. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  266. package/dist/tasks/run/load-task.js +1 -1
  267. package/dist/tasks/scheduler-binding.js +20 -238
  268. package/dist/tasks/scheduler-invocation.js +136 -244
  269. package/dist/tasks/scheduler-lock.js +53 -0
  270. package/dist/tasks/scheduler-sync.js +368 -679
  271. package/dist/tasks/source/parse-task-source.js +55 -9
  272. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  273. package/dist/tasks/source/task-to-v4.js +464 -88
  274. package/dist/workflows/authoring/authoring.js +3 -12
  275. package/dist/workflows/compile.js +211 -0
  276. package/dist/workflows/concurrency-policy.js +13 -74
  277. package/dist/workflows/exec/child-invocation.js +3 -17
  278. package/dist/workflows/exec/child-workflow.js +32 -141
  279. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  280. package/dist/workflows/exec/environment.js +98 -0
  281. package/dist/workflows/exec/exec-unit.js +33 -140
  282. package/dist/workflows/exec/frozen-judge.js +7 -59
  283. package/dist/workflows/exec/native-executor.js +82 -341
  284. package/dist/workflows/exec/param-secrets.js +29 -47
  285. package/dist/workflows/exec/run-workflow.js +154 -387
  286. package/dist/workflows/exec/scheduler.js +9 -36
  287. package/dist/workflows/exec/step-work.js +127 -430
  288. package/dist/workflows/exec/unit-dispatch.js +11 -63
  289. package/dist/workflows/exec/unit-writer.js +8 -52
  290. package/dist/workflows/exec/worktree.js +39 -273
  291. package/dist/workflows/freeze/child-output-references.js +4 -15
  292. package/dist/workflows/freeze/environment.js +99 -92
  293. package/dist/workflows/freeze/freeze.js +172 -0
  294. package/dist/workflows/freeze/step-values.js +19 -21
  295. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  296. package/dist/workflows/freeze/targets/command.js +10 -33
  297. package/dist/workflows/freeze/targets/script.js +5 -12
  298. package/dist/workflows/freeze/targets/shell.js +3 -6
  299. package/dist/workflows/freeze/targets/task.js +25 -80
  300. package/dist/workflows/freeze/task-bindings.js +20 -67
  301. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  302. package/dist/workflows/ir/params.js +6 -51
  303. package/dist/workflows/ir/plan-hash.js +2 -34
  304. package/dist/workflows/parser.js +140 -43
  305. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  306. package/dist/workflows/renderer.js +36 -69
  307. package/dist/workflows/resource-limits.js +12 -120
  308. package/dist/workflows/runtime/agent-identity.js +8 -40
  309. package/dist/workflows/runtime/run-outputs.js +3 -6
  310. package/dist/workflows/runtime/run-plan.js +316 -0
  311. package/dist/workflows/runtime/runs.js +48 -200
  312. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  313. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  314. package/dist/workflows/validate-summary.js +2 -7
  315. package/docs/integration/bundling-akm.md +49 -42
  316. package/docs/migration/README.md +1 -0
  317. package/docs/migration/release-notes/0.9.17.md +43 -0
  318. package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
  319. package/docs/reference/cli.md +232 -135
  320. package/docs/reference/configuration.md +71 -57
  321. package/docs/reference/data-and-telemetry.md +20 -21
  322. package/docs/reference/tasks.md +105 -39
  323. package/docs/reference/workflow-schema.md +14 -18
  324. package/docs/reference/workflows.md +6 -9
  325. package/package.json +1 -1
  326. package/schemas/akm-config.json +115 -738
  327. package/schemas/akm-workflow.json +1 -0
  328. package/dist/assets/improve-strategies/graph-refresh.json +0 -15
  329. package/dist/assets/prompts/contradiction-judge.md +0 -33
  330. package/dist/assets/prompts/graph-extract-system.md +0 -1
  331. package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
  332. package/dist/assets/prompts/metadata-enhance-system.md +0 -1
  333. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
  334. package/dist/commands/health/advisories.js +0 -150
  335. package/dist/commands/health/metrics.js +0 -329
  336. package/dist/commands/health/surfaces.js +0 -102
  337. package/dist/commands/improve/anti-collapse.js +0 -83
  338. package/dist/commands/improve/collapse-detector.js +0 -432
  339. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  340. package/dist/commands/improve/consolidate/merge.js +0 -149
  341. package/dist/commands/improve/distill/promote-memory.js +0 -291
  342. package/dist/commands/improve/distill/quality-gate.js +0 -337
  343. package/dist/commands/improve/eval-cases.js +0 -52
  344. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  345. package/dist/commands/improve/proposal-envelope.js +0 -31
  346. package/dist/commands/improve/run-context.js +0 -123
  347. package/dist/commands/improve/shared.js +0 -31
  348. package/dist/commands/improve/source-identity.js +0 -28
  349. package/dist/commands/improve/triage.js +0 -96
  350. package/dist/commands/proposal/drain-policies.js +0 -151
  351. package/dist/commands/sources/update-transaction.js +0 -220
  352. package/dist/core/action-contributors.js +0 -28
  353. package/dist/core/config/config-version-shim.js +0 -101
  354. package/dist/core/fs-txn.js +0 -405
  355. package/dist/core/lexical-score.js +0 -25
  356. package/dist/core/maintenance-barrier.js +0 -167
  357. package/dist/execution/executable-identity.js +0 -105
  358. package/dist/execution/guarded-source.js +0 -427
  359. package/dist/indexer/db/graph-db.js +0 -444
  360. package/dist/indexer/graph/graph-boost.js +0 -427
  361. package/dist/indexer/graph/graph-dedup.js +0 -95
  362. package/dist/indexer/graph/graph-extraction.js +0 -1108
  363. package/dist/indexer/search/name-match.js +0 -35
  364. package/dist/indexer/search/ranking-contributors.js +0 -515
  365. package/dist/indexer/search/ranking-types.js +0 -4
  366. package/dist/indexer/walk/project-context.js +0 -192
  367. package/dist/integrations/agent/execution-cascade.js +0 -566
  368. package/dist/integrations/agent/execution-definitions.js +0 -202
  369. package/dist/integrations/agent/execution-lowering.js +0 -841
  370. package/dist/integrations/agent/execution-preparation.js +0 -98
  371. package/dist/integrations/agent/inline-execution.js +0 -74
  372. package/dist/llm/graph-extract.js +0 -728
  373. package/dist/llm/metadata-enhance.js +0 -96
  374. package/dist/registry/create-provider-registry.js +0 -29
  375. package/dist/registry/pinned-request-helper.js +0 -247
  376. package/dist/registry/pinned-transport.js +0 -717
  377. package/dist/sources/providers/index.js +0 -14
  378. package/dist/storage/engines/sqlite-migrations.js +0 -271
  379. package/dist/storage/repositories/canaries-repository.js +0 -107
  380. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  381. package/dist/storage/repositories/registry-cache.js +0 -113
  382. package/dist/tasks/scheduler-sync-preview.js +0 -52
  383. package/dist/tasks/source/task-to-v3.js +0 -507
  384. package/dist/workflows/freeze/resolve-steps.js +0 -86
  385. package/dist/workflows/freeze/source-freeze.js +0 -64
  386. package/dist/workflows/ir/compile.js +0 -321
  387. package/dist/workflows/ir/environment-v4.js +0 -330
  388. package/dist/workflows/ir/freeze-v4.js +0 -153
  389. package/dist/workflows/ir/schema-v4.js +0 -745
  390. package/dist/workflows/ir/schema.js +0 -354
  391. package/dist/workflows/program/schema.js +0 -77
  392. package/dist/workflows/runtime/checkin.js +0 -57
  393. package/dist/workflows/runtime/plan-classifier.js +0 -196
  394. package/dist/workflows/runtime/unit-checkin.js +0 -45
  395. package/dist/workflows/runtime/unit-phases.js +0 -20
  396. package/dist/workflows/schema.js +0 -4
  397. package/dist/workflows/source-ir/compile.js +0 -200
  398. package/dist/workflows/source-ir/program.js +0 -50
  399. package/dist/workflows/source-ir/result.js +0 -26
  400. package/dist/workflows/source-ir/schema.js +0 -786
  401. package/dist/workflows/source-ir/triggers.js +0 -79
  402. package/dist/workflows/source-ir/uses.js +0 -40
  403. 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,507 +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
- /** Pure, byte-producing legacy-task to task-v3 migration planner. */
5
- import crypto from "node:crypto";
6
- import path from "node:path";
7
- import { LineCounter, parseDocument, stringify as stringifyYaml } from "yaml";
8
- import { bundleRefToString, parseBundleRef } from "../../core/asset/asset-ref.js";
9
- import { formatExtraParamsIssue, validateExtraParams } from "../../core/extra-params.js";
10
- import { WORKFLOW_ENV_VAR_NAME_PATTERN, WORKFLOW_MAX_TIMEOUT_MS } from "../../workflows/resource-limits.js";
11
- import { validateTaskId } from "../task-id.js";
12
- import { assertBoundedTaskYamlDocument, TASK_V3_MAX_REDACT_NAMES } from "./bounded-document.js";
13
- import { classifyTaskV3Uses, parseTaskV3Yaml } from "./task-source-v3-frozen.js";
14
- const V2_KEYS = new Set([
15
- "version",
16
- "name",
17
- "description",
18
- "when_to_use",
19
- "tags",
20
- "schedule",
21
- "enabled",
22
- "workflow",
23
- "prompt",
24
- "command",
25
- "params",
26
- "engine",
27
- "model",
28
- "timeoutMs",
29
- "maxSteps",
30
- "maxRetries",
31
- "llm",
32
- "redact",
33
- ]);
34
- const V2_SHARED_KEYS = new Set([
35
- "version",
36
- "name",
37
- "description",
38
- "when_to_use",
39
- "tags",
40
- "schedule",
41
- "enabled",
42
- "redact",
43
- ]);
44
- const V2_LLM_KEYS = new Set([
45
- "temperature",
46
- "maxTokens",
47
- "supportsJsonSchema",
48
- "extraParams",
49
- "contextLength",
50
- "enableThinking",
51
- "reasoningEffort",
52
- ]);
53
- const SAFE_V2_COMMAND_TOKEN = /^[A-Za-z0-9_./:=+,-]+$/;
54
- const SHELL_ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
55
- /**
56
- * V2 executed argv directly, while v3 `run:` enters a host shell. An explicit
57
- * path bypasses shell aliases/builtins; `akm` is the one bare executable whose
58
- * v3 runtime resolution is contractually pinned to the current installation.
59
- */
60
- function shellStableV2Executable(executable) {
61
- return executable === "akm" || executable.includes("/");
62
- }
63
- /**
64
- * `env NAME=value... cmd args...` is env(1) itself resolving and exec'ing
65
- * `cmd` via its own PATH search — that lookup happens inside env's execvp()
66
- * regardless of whether env was launched by direct execve (v2) or by a host
67
- * shell (v3 `run:`). The shell-vs-argv divergence `shellStableV2Executable`
68
- * guards against (bare names shadowed by shell aliases/builtins/functions)
69
- * therefore does not apply to whatever env ultimately invokes, so skip past
70
- * a leading `env` and its `NAME=value` assignments to find the real target.
71
- * Returns the original tokens, unchanged, when there is no such target
72
- * (e.g. `env` with nothing after its assignments).
73
- */
74
- function skipEnvAssignmentPrefix(tokens) {
75
- if (tokens[0] !== "env")
76
- return { tokens, envWrapped: false };
77
- let index = 1;
78
- while (index < tokens.length && SHELL_ASSIGNMENT_WORD.test(tokens[index]))
79
- index += 1;
80
- if (index >= tokens.length)
81
- return { tokens, envWrapped: false };
82
- return { tokens: tokens.slice(index), envWrapped: true };
83
- }
84
- const KNOWN_PROMPT_REF_FAMILIES = new Set([
85
- "agents",
86
- "commands",
87
- "env",
88
- "facts",
89
- "instructions",
90
- "knowledge",
91
- "lessons",
92
- "memories",
93
- "scripts",
94
- "secrets",
95
- "sessions",
96
- "skills",
97
- "tasks",
98
- "workflows",
99
- ]);
100
- function hash(bytes) {
101
- return crypto.createHash("sha256").update(bytes).digest("hex");
102
- }
103
- function base(input) {
104
- return {
105
- filePath: input.filePath,
106
- before: Buffer.from(input.bytes),
107
- beforeHash: hash(input.bytes),
108
- mode: input.mode,
109
- writable: input.writable,
110
- ...(input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {}),
111
- ...(input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}),
112
- };
113
- }
114
- /**
115
- * #902: the one blocker with an unambiguous remedy. The sibling shell-safety
116
- * reasons need a case-by-case judgement and stay reason-only.
117
- */
118
- const ARGV_ARRAY_BLOCK_DETAIL = "Manual conversion required: an array `command:` has no safe v3 `run:` string. Rewrite it by hand as " +
119
- "`run:` (string) plus `shell:` — see docs/migration/v0.9.1-to-v0.9.2.md for the full v2 to v4 field mapping.";
120
- function blocked(input, reason, detail) {
121
- return Object.freeze({ status: "blocked", ...base(input), reason, ...(detail ? { detail } : {}) });
122
- }
123
- function plainRecord(value, label) {
124
- if (value === null || typeof value !== "object" || Array.isArray(value))
125
- throw new Error(`${label} must be a mapping`);
126
- const prototype = Object.getPrototypeOf(value);
127
- if (prototype !== Object.prototype && prototype !== null)
128
- throw new Error(`${label} must use a plain or null prototype`);
129
- return value;
130
- }
131
- function exactString(value, label, nonempty = false) {
132
- if (typeof value !== "string" || (nonempty && value.trim().length === 0)) {
133
- throw new Error(`${label} must be ${nonempty ? "a non-empty " : "a "}string`);
134
- }
135
- return value;
136
- }
137
- function optionalString(value, label) {
138
- if (value === undefined || value === null)
139
- return undefined;
140
- return exactString(value, label);
141
- }
142
- function parseLegacyTaskYaml(input) {
143
- let source;
144
- try {
145
- source = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(input.bytes);
146
- }
147
- catch {
148
- throw new Error("task YAML contains invalid UTF-8 bytes");
149
- }
150
- const lineCounter = new LineCounter();
151
- let document;
152
- try {
153
- document = parseDocument(source, { lineCounter, uniqueKeys: true });
154
- }
155
- catch (cause) {
156
- throw new Error(`invalid YAML: ${cause instanceof Error ? cause.message : String(cause)}`);
157
- }
158
- const [parseError] = document.errors;
159
- if (parseError)
160
- throw new Error(`invalid YAML: ${parseError.message.split("\n")[0]}`);
161
- const [parseWarning] = document.warnings;
162
- if (parseWarning)
163
- throw new Error(`unsupported YAML construct: ${parseWarning.message}`);
164
- assertBoundedTaskYamlDocument(document, {
165
- filePath: input.filePath,
166
- sourceLabel: "task v2 migration source",
167
- lineCounter,
168
- });
169
- return { data: plainRecord(document.toJS({ maxAliasCount: 0 }), "task YAML"), source };
170
- }
171
- function validateCommonV2(data) {
172
- const unknown = Object.keys(data).filter((key) => !V2_KEYS.has(key));
173
- if (unknown.length > 0)
174
- throw new Error(`unknown v2 field(s): ${unknown.join(", ")}`);
175
- exactString(data.schedule, "schedule", true);
176
- if (data.enabled !== undefined && typeof data.enabled !== "boolean")
177
- throw new Error("enabled must be a boolean");
178
- for (const key of ["name", "description", "when_to_use"])
179
- optionalString(data[key], key);
180
- if (data.tags !== undefined && data.tags !== null) {
181
- if (!Array.isArray(data.tags) || data.tags.some((entry) => typeof entry !== "string" || entry.length === 0)) {
182
- throw new Error("tags must be an array of non-empty strings");
183
- }
184
- }
185
- if (data.timeoutMs !== undefined && data.timeoutMs !== null) {
186
- if (!Number.isInteger(data.timeoutMs) ||
187
- data.timeoutMs < 1 ||
188
- data.timeoutMs > WORKFLOW_MAX_TIMEOUT_MS) {
189
- throw new Error(`timeoutMs must be null or an integer from 1 through ${WORKFLOW_MAX_TIMEOUT_MS}`);
190
- }
191
- }
192
- if (data.redact !== undefined && data.redact !== null) {
193
- if (!Array.isArray(data.redact) ||
194
- data.redact.length > TASK_V3_MAX_REDACT_NAMES ||
195
- data.redact.some((entry) => typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry))) {
196
- throw new Error("redact must contain only bounded environment variable names");
197
- }
198
- }
199
- }
200
- function validateTargetFields(data, allowed) {
201
- const targetFields = new Set([...allowed, "workflow", "prompt", "command"]);
202
- const invalid = Object.keys(data).filter((key) => !V2_SHARED_KEYS.has(key) && !targetFields.has(key));
203
- if (invalid.length > 0)
204
- throw new Error(`field(s) not valid for this target: ${invalid.join(", ")}`);
205
- }
206
- function validateV2Llm(value) {
207
- if (value === undefined)
208
- return undefined;
209
- const llm = plainRecord(value, "llm");
210
- const unknown = Object.keys(llm).filter((key) => !V2_LLM_KEYS.has(key));
211
- if (unknown.length > 0)
212
- throw new Error(`llm has unknown field(s): ${unknown.join(", ")}`);
213
- if (llm.temperature !== undefined && (typeof llm.temperature !== "number" || !Number.isFinite(llm.temperature))) {
214
- throw new Error("llm.temperature must be a finite number");
215
- }
216
- for (const key of ["maxTokens", "contextLength"]) {
217
- if (llm[key] !== undefined && (!Number.isInteger(llm[key]) || llm[key] <= 0)) {
218
- throw new Error(`llm.${key} must be a positive integer`);
219
- }
220
- }
221
- for (const key of ["supportsJsonSchema", "enableThinking"]) {
222
- if (llm[key] !== undefined && typeof llm[key] !== "boolean")
223
- throw new Error(`llm.${key} must be a boolean`);
224
- }
225
- if (llm.reasoningEffort !== undefined && (typeof llm.reasoningEffort !== "string" || !llm.reasoningEffort.trim())) {
226
- throw new Error("llm.reasoningEffort must be a non-empty string");
227
- }
228
- if (llm.extraParams !== undefined) {
229
- const issue = validateExtraParams(llm.extraParams)[0];
230
- if (issue)
231
- throw new Error(formatExtraParamsIssue("llm.extraParams", issue));
232
- }
233
- return llm;
234
- }
235
- function commonAkm(data) {
236
- const akm = {
237
- schedule: exactString(data.schedule, "schedule", true),
238
- enabled: data.enabled === undefined ? true : data.enabled,
239
- };
240
- for (const key of ["description", "when_to_use", "tags"]) {
241
- if (data[key] !== undefined && data[key] !== null)
242
- akm[key] = data[key];
243
- }
244
- return akm;
245
- }
246
- function addRuntimeOverrides(data, akm) {
247
- for (const key of ["engine", "model"]) {
248
- const value = optionalString(data[key], key);
249
- if (value)
250
- akm[key] = value;
251
- }
252
- const llm = validateV2Llm(data.llm);
253
- if (llm !== undefined)
254
- akm.inference = llm;
255
- if (data.timeoutMs !== undefined)
256
- akm.timeout = data.timeoutMs;
257
- if (data.redact !== undefined && data.redact !== null) {
258
- akm.redact = [...new Set(data.redact)];
259
- }
260
- }
261
- function addSharedNonPromptOverrides(data, akm) {
262
- if (data.timeoutMs !== undefined)
263
- akm.timeout = data.timeoutMs;
264
- if (data.redact !== undefined && data.redact !== null) {
265
- akm.redact = [...new Set(data.redact)];
266
- }
267
- }
268
- function promptSourceKind(raw) {
269
- const trimmed = raw.trim();
270
- if (trimmed.startsWith("./") ||
271
- trimmed.startsWith("../") ||
272
- path.isAbsolute(trimmed) ||
273
- /^[A-Za-z]:[\\/]/.test(trimmed)) {
274
- return "file";
275
- }
276
- try {
277
- const parsed = parseBundleRef(trimmed);
278
- const family = parsed.conceptId.split("/", 1)[0] ?? "";
279
- if (bundleRefToString(parsed) !== trimmed || !parsed.conceptId.includes("/")) {
280
- return "inline";
281
- }
282
- if (!KNOWN_PROMPT_REF_FAMILIES.has(family))
283
- return parsed.bundle === undefined ? "inline" : "other-ref";
284
- if (family === "agents")
285
- return "agent";
286
- if (family === "commands")
287
- return "command";
288
- return "other-ref";
289
- }
290
- catch {
291
- return "inline";
292
- }
293
- }
294
- function migratedObject(data) {
295
- validateCommonV2(data);
296
- const targets = ["workflow", "prompt", "command"].filter((key) => Object.hasOwn(data, key) && data[key] !== null && data[key] !== "");
297
- if (targets.length !== 1)
298
- throw new Error("v2 task must declare exactly one of workflow, prompt, or command");
299
- const output = { version: 3 };
300
- if (data.name !== undefined && data.name !== null)
301
- output.name = data.name;
302
- const akm = commonAkm(data);
303
- if (targets[0] === "workflow") {
304
- validateTargetFields(data, ["params", "timeoutMs", "maxSteps", "maxRetries"]);
305
- const ref = exactString(data.workflow, "workflow", true).trim();
306
- let target;
307
- try {
308
- target = classifyTaskV3Uses(ref);
309
- }
310
- catch {
311
- throw new Error("workflow is not a canonical v3 asset ref");
312
- }
313
- if (target.kind !== "workflow")
314
- throw new Error("workflow target is not a workflows/ ref");
315
- output.uses = ref;
316
- if (data.params !== undefined && data.params !== null) {
317
- const params = plainRecord(data.params, "params");
318
- output.with = params;
319
- }
320
- if (data.maxSteps !== undefined && data.maxSteps !== null) {
321
- if (!Number.isSafeInteger(data.maxSteps) || data.maxSteps < 1)
322
- throw new Error("maxSteps must be positive");
323
- akm.maxSteps = data.maxSteps;
324
- }
325
- if (data.maxRetries !== undefined && data.maxRetries !== null) {
326
- if (!Number.isSafeInteger(data.maxRetries) || data.maxRetries < 0) {
327
- throw new Error("maxRetries must be a non-negative integer");
328
- }
329
- akm.maxRetries = data.maxRetries;
330
- }
331
- addSharedNonPromptOverrides(data, akm);
332
- }
333
- else if (targets[0] === "prompt") {
334
- validateTargetFields(data, ["engine", "model", "timeoutMs", "llm"]);
335
- const prompt = exactString(data.prompt, "prompt", true).trim();
336
- const kind = promptSourceKind(prompt);
337
- if (kind === "file")
338
- return "dynamic-file-read-cannot-be-inlined-without-changing-semantics";
339
- if (kind === "agent")
340
- return "agent-ref-has-persona-but-no-command-work";
341
- if (kind === "other-ref")
342
- return "non-command-asset-has-no-v3-command-ref-equivalent";
343
- if (kind === "command")
344
- output.uses = prompt;
345
- else {
346
- output.uses = "akm/command";
347
- output.with = { content: prompt };
348
- }
349
- addRuntimeOverrides(data, akm);
350
- }
351
- else {
352
- validateTargetFields(data, ["timeoutMs"]);
353
- if (Array.isArray(data.command))
354
- return "argv-array-has-no-portable-shell-string";
355
- const command = exactString(data.command, "command", true).trim();
356
- if (/['"\\]/.test(command))
357
- return "shell-quoting-changes-v2-whitespace-split-semantics";
358
- const tokens = command.split(/\s+/).filter(Boolean);
359
- if (tokens.length === 0 || tokens.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
360
- return "shell-operators-change-v2-literal-argv-semantics";
361
- }
362
- const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens);
363
- const executable = targetTokens[0];
364
- if (SHELL_ASSIGNMENT_WORD.test(executable) || (!envWrapped && !shellStableV2Executable(executable))) {
365
- return "shell-command-resolution-changes-v2-literal-argv-semantics";
366
- }
367
- output.run = tokens.join(" ");
368
- addSharedNonPromptOverrides(data, akm);
369
- }
370
- output.akm = akm;
371
- return output;
372
- }
373
- function isReason(value) {
374
- return typeof value === "string";
375
- }
376
- /** Convert one already-normalized legacy record directly to final task v3. */
377
- export function planLegacyTaskDataToV3(input, data) {
378
- if (data.version !== 2) {
379
- return blocked(input, "unsupported-task-version", `expected normalized legacy version 2, got ${String(data.version)}`);
380
- }
381
- if (!input.writable || input.onDiskWritable === false) {
382
- return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
383
- }
384
- try {
385
- validateTaskId(path.basename(input.filePath, ".yml"));
386
- }
387
- catch (cause) {
388
- return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
389
- }
390
- let migrated;
391
- try {
392
- migrated = migratedObject(data);
393
- }
394
- catch (cause) {
395
- return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
396
- }
397
- if (isReason(migrated)) {
398
- const detail = migrated === "argv-array-has-no-portable-shell-string" ? ARGV_ARRAY_BLOCK_DETAIL : undefined;
399
- return blocked(input, migrated, detail);
400
- }
401
- const after = Buffer.from(stringifyYaml(migrated), "utf8");
402
- try {
403
- parseTaskV3Yaml({
404
- yaml: after.toString("utf8"),
405
- filePath: input.filePath,
406
- ...(input.containmentRoot ? { workspaceRoot: input.containmentRoot } : {}),
407
- });
408
- }
409
- catch (cause) {
410
- return blocked(input, "generated-v3-validation-failed", cause instanceof Error ? cause.message : String(cause));
411
- }
412
- return Object.freeze({
413
- status: "changed",
414
- ...base(input),
415
- reason: "task-converted",
416
- after,
417
- afterHash: hash(after),
418
- });
419
- }
420
- /** Plan exactly one source file without touching disk. */
421
- export function planTaskToV3File(input) {
422
- let data;
423
- let source;
424
- try {
425
- ({ data, source } = parseLegacyTaskYaml(input));
426
- }
427
- catch (cause) {
428
- return blocked(input, "invalid-task-yaml", cause instanceof Error ? cause.message : String(cause));
429
- }
430
- if (data.version === 3) {
431
- try {
432
- parseTaskV3Yaml({
433
- yaml: source,
434
- filePath: input.filePath,
435
- ...(input.containmentRoot ? { workspaceRoot: input.containmentRoot } : {}),
436
- });
437
- return Object.freeze({ status: "skipped", ...base(input), reason: "already-v3" });
438
- }
439
- catch (cause) {
440
- return blocked(input, "invalid-v3-task", cause instanceof Error ? cause.message : String(cause));
441
- }
442
- }
443
- if (data.version === 4) {
444
- // Generation 1 owns v2 only. Do not validate v4 here: generation 2 must
445
- // be allowed to recognize and remove the retired schedule[].enabled field
446
- // before the current runtime parser sees those bytes.
447
- return Object.freeze({ status: "skipped", ...base(input), reason: "already-v4" });
448
- }
449
- if (data.version !== 2) {
450
- return blocked(input, "unsupported-task-version", `expected version 2, 3, or 4, got ${String(data.version)}`);
451
- }
452
- return planLegacyTaskDataToV3(input, data);
453
- }
454
- function generationFor(files) {
455
- const digest = crypto.createHash("sha256");
456
- digest.update("akm-task-to-v3-plan-v1\0");
457
- for (const file of files) {
458
- digest.update(file.filePath);
459
- digest.update("\0");
460
- digest.update(file.status);
461
- digest.update("\0");
462
- digest.update(file.reason);
463
- digest.update("\0");
464
- digest.update(String(file.mode));
465
- digest.update("\0");
466
- digest.update(file.writable ? "writable" : "read-only");
467
- digest.update("\0");
468
- digest.update(file.onDiskWritable === false ? "disk-read-only" : "disk-writable-or-unspecified");
469
- digest.update("\0");
470
- if (file.containmentRoot)
471
- digest.update(file.containmentRoot);
472
- digest.update("\0");
473
- digest.update(file.beforeHash);
474
- digest.update("\0");
475
- if (file.status === "changed")
476
- digest.update(file.afterHash);
477
- digest.update("\0");
478
- if (file.detail)
479
- digest.update(file.detail);
480
- digest.update("\0");
481
- }
482
- return digest.digest("hex");
483
- }
484
- /** Build/fingerprint a plan from already-derived immutable outcomes. */
485
- export function taskToV3PlanFromOutcomes(outcomes) {
486
- const files = [...outcomes].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
487
- for (let index = 1; index < files.length; index += 1) {
488
- const previous = files[index - 1];
489
- const current = files[index];
490
- if (previous && current && path.resolve(previous.filePath) === path.resolve(current.filePath)) {
491
- throw new Error(`duplicate task migration file path: ${current.filePath}`);
492
- }
493
- }
494
- return Object.freeze({ schemaVersion: 1, generation: generationFor(files), files: Object.freeze(files) });
495
- }
496
- /** Plan a complete, stable file set. Input order cannot change the result. */
497
- export function planTaskToV3Migration(inputs) {
498
- const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
499
- let previous;
500
- for (const current of sorted) {
501
- if (previous && path.resolve(previous.filePath) === path.resolve(current.filePath)) {
502
- throw new Error(`duplicate task migration file path: ${current.filePath}`);
503
- }
504
- previous = current;
505
- }
506
- return taskToV3PlanFromOutcomes(sorted.map(planTaskToV3File));
507
- }