akm-cli 0.9.31 → 0.10.261001-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/CHANGELOG.md +409 -0
  2. package/STABILITY.md +99 -57
  3. package/dist/api-node.mjs +20 -0
  4. package/dist/api.d.ts +23 -0
  5. package/dist/api.js +45 -0
  6. package/dist/assets/hints/cli-hints-full.md +15 -29
  7. package/dist/assets/hints/cli-hints-short.md +2 -2
  8. package/dist/assets/improve-strategies/default.json +3 -3
  9. package/dist/assets/prompts/consolidate-pair.md +9 -7
  10. package/dist/assets/stash-skeleton/README.md +1 -1
  11. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  12. package/dist/cli/shared.js +31 -48
  13. package/dist/cli/unknown-flags.js +6 -43
  14. package/dist/cli.js +8 -34
  15. package/dist/commands/agent/contribute-cli.js +1 -1
  16. package/dist/commands/completions.js +1 -2
  17. package/dist/commands/config-cli.js +5 -28
  18. package/dist/commands/env/env-cli.js +5 -5
  19. package/dist/commands/env/secret-cli.js +2 -2
  20. package/dist/commands/feedback-cli.js +75 -49
  21. package/dist/commands/health/checks.js +41 -16
  22. package/dist/commands/health/plugin-staleness.js +52 -22
  23. package/dist/commands/improve/autonomy-gate.js +5 -3
  24. package/dist/commands/improve/consolidate/chunking.js +3 -10
  25. package/dist/commands/improve/consolidate/continuity-check.js +4 -4
  26. package/dist/commands/improve/consolidate/pair-pass.js +29 -10
  27. package/dist/commands/improve/consolidate.js +10 -65
  28. package/dist/commands/improve/distill/lesson-update.js +91 -0
  29. package/dist/commands/improve/distill-guards.js +1 -43
  30. package/dist/commands/improve/distill.js +148 -21
  31. package/dist/commands/improve/eligibility.js +14 -1
  32. package/dist/commands/improve/extract-cli.js +1 -1
  33. package/dist/commands/improve/extract-prompt.js +17 -7
  34. package/dist/commands/improve/extract.js +5 -7
  35. package/dist/commands/improve/improve-cli.js +92 -106
  36. package/dist/commands/improve/improve-strategies.js +8 -12
  37. package/dist/commands/improve/improve.js +134 -52
  38. package/dist/commands/improve/loop-stages.js +18 -5
  39. package/dist/commands/improve/planner.js +0 -1
  40. package/dist/commands/improve/preparation.js +40 -99
  41. package/dist/commands/improve/proactive-maintenance.js +2 -2
  42. package/dist/commands/improve/reflect-noise.js +3 -55
  43. package/dist/commands/improve/reflect.js +29 -34
  44. package/dist/commands/improve/retrieval-queries.js +37 -0
  45. package/dist/commands/improve/retrieval-scope.js +2 -2
  46. package/dist/commands/improve/salience.js +2 -9
  47. package/dist/commands/improve/session-asset.js +4 -1
  48. package/dist/commands/improve/stage.js +23 -12
  49. package/dist/commands/lint/index.js +5 -20
  50. package/dist/commands/observability-cli.js +3 -9
  51. package/dist/commands/proposal/drain.js +43 -6
  52. package/dist/commands/proposal/proposal-cli.js +11 -31
  53. package/dist/commands/proposal/repository.js +20 -14
  54. package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
  55. package/dist/commands/read/knowledge.js +3 -3
  56. package/dist/commands/read/remember-cli.js +0 -13
  57. package/dist/commands/read/search-cli.js +29 -97
  58. package/dist/commands/read/search.js +0 -11
  59. package/dist/commands/read/show.js +0 -19
  60. package/dist/commands/sources/plugin-upgrade.js +164 -101
  61. package/dist/commands/sources/sources-cli.js +1 -15
  62. package/dist/commands/sources/stash-cli.js +6 -14
  63. package/dist/commands/tasks/tasks-cli.js +4 -115
  64. package/dist/commands/workflow/plan.js +11 -33
  65. package/dist/commands/workflow-cli.js +2 -7
  66. package/dist/core/adapter/adapter-ids.js +1 -2
  67. package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
  68. package/dist/core/adapter/adapters/akm-adapter.js +9 -48
  69. package/dist/core/adapter/adapters/akm-lint.js +10 -26
  70. package/dist/core/adapter/adapters/akm-metadata.js +2 -72
  71. package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
  72. package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
  73. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
  74. package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
  75. package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
  76. package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
  77. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
  78. package/dist/core/adapter/recognize-match.js +3 -4
  79. package/dist/core/common.js +18 -2
  80. package/dist/core/config/config-schema.js +12 -15
  81. package/dist/core/config/config-types.js +6 -15
  82. package/dist/core/config/config-walker.js +6 -23
  83. package/dist/core/config/config.js +17 -80
  84. package/dist/core/config/engine-semantics.js +7 -3
  85. package/dist/core/config/schema/engines.js +7 -7
  86. package/dist/core/config/schema/improve-processes.js +10 -63
  87. package/dist/core/config/schema/improve.js +2 -21
  88. package/dist/core/config/schema/index-config.js +6 -39
  89. package/dist/core/env-secret-ref.js +2 -45
  90. package/dist/core/errors.js +1 -2
  91. package/dist/core/extra-params.js +2 -86
  92. package/dist/core/file-lock.js +2 -6
  93. package/dist/core/improve-result.js +13 -1
  94. package/dist/core/mutation-target.js +2 -2
  95. package/dist/core/paths.js +4 -0
  96. package/dist/core/recognition-util.js +4 -5
  97. package/dist/core/run-lock.js +1 -1
  98. package/dist/core/subprocess.js +49 -0
  99. package/dist/core/warn.js +21 -4
  100. package/dist/core/write-source.js +3 -3
  101. package/dist/execution/target-ref.js +1 -2
  102. package/dist/indexer/indexer.js +15 -6
  103. package/dist/indexer/passes/memory-inference.js +15 -6
  104. package/dist/indexer/search/db-search.js +49 -36
  105. package/dist/indexer/search/fts-query.js +0 -19
  106. package/dist/indexer/search/ranking.js +29 -1
  107. package/dist/indexer/usage/usage-events.js +21 -16
  108. package/dist/integrations/agent/engine-resolution.js +5 -2
  109. package/dist/integrations/agent/index.js +1 -1
  110. package/dist/integrations/agent/profiles.js +41 -98
  111. package/dist/integrations/agent/request-lowering.js +3 -3
  112. package/dist/integrations/harnesses/aider/index.js +5 -0
  113. package/dist/integrations/harnesses/amazonq/index.js +1 -0
  114. package/dist/integrations/harnesses/claude/config-import.js +2 -3
  115. package/dist/integrations/harnesses/claude/index.js +5 -0
  116. package/dist/integrations/harnesses/codex/index.js +1 -0
  117. package/dist/integrations/harnesses/copilot/index.js +1 -0
  118. package/dist/integrations/harnesses/gemini/index.js +1 -0
  119. package/dist/integrations/harnesses/index.js +18 -39
  120. package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
  121. package/dist/integrations/harnesses/opencode/config-import.js +121 -52
  122. package/dist/integrations/harnesses/opencode/index.js +22 -0
  123. package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
  124. package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
  125. package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
  126. package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
  127. package/dist/integrations/harnesses/opencode/session-log.js +104 -115
  128. package/dist/integrations/harnesses/opencode/version.js +98 -0
  129. package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
  130. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
  131. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
  132. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
  133. package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
  134. package/dist/integrations/harnesses/openhands/index.js +1 -0
  135. package/dist/integrations/harnesses/pi/index.js +1 -0
  136. package/dist/integrations/harnesses/shared.js +2 -0
  137. package/dist/integrations/harnesses/types.js +2 -0
  138. package/dist/llm/client.js +41 -11
  139. package/dist/output/cli-hints.js +1 -1
  140. package/dist/output/context.js +10 -19
  141. package/dist/output/format-exempt.js +5 -8
  142. package/dist/output/shapes/helpers.js +1 -22
  143. package/dist/output/shapes/passthrough.js +0 -1
  144. package/dist/output/shapes.js +3 -31
  145. package/dist/output/stdout.js +5 -1
  146. package/dist/output/text/command-format.js +6 -1
  147. package/dist/output/text/workflow-format.js +4 -22
  148. package/dist/scripts/akm-migrate-node.js +15745 -16711
  149. package/dist/scripts/akm-migrate.js +16318 -17280
  150. package/dist/setup/detect.js +10 -4
  151. package/dist/setup/harness-config-import.js +5 -14
  152. package/dist/setup/setup.js +1 -1
  153. package/dist/setup/steps/tasks.js +12 -13
  154. package/dist/sources/providers/git-stash.js +94 -13
  155. package/dist/storage/repositories/index-utility-repository.js +2 -32
  156. package/dist/storage/repositories/index-vec-repository.js +4 -0
  157. package/dist/storage/repositories/task-history-repository.js +0 -5
  158. package/dist/storage/repositories/workflow-runs-repository.js +5 -15
  159. package/dist/tasks/embedded.js +2 -1
  160. package/dist/tasks/run/run-command-task.js +9 -1
  161. package/dist/tasks/run/run-workflow-task.js +4 -3
  162. package/dist/tasks/run/task-history.js +0 -2
  163. package/dist/tasks/run/task-log.js +38 -1
  164. package/dist/tasks/schedule-gates.js +39 -0
  165. package/dist/tasks/scheduler-binding.js +0 -16
  166. package/dist/tasks/scheduler-sync.js +3 -97
  167. package/dist/tasks/source/bounded-document.js +1 -1
  168. package/dist/tasks/source/task-source-v4.js +2 -12
  169. package/dist/tasks/task-run-reserved-flags.js +2 -31
  170. package/dist/workflows/authoring/authoring.js +6 -6
  171. package/dist/workflows/compile.js +8 -65
  172. package/dist/workflows/exec/child-workflow.js +22 -3
  173. package/dist/workflows/exec/native-executor.js +12 -147
  174. package/dist/workflows/exec/run-workflow.js +31 -103
  175. package/dist/workflows/exec/step-work.js +9 -178
  176. package/dist/workflows/exec/unit-dispatch.js +0 -10
  177. package/dist/workflows/freeze/environment.js +3 -44
  178. package/dist/workflows/freeze/freeze.js +8 -41
  179. package/dist/workflows/freeze/targets/child-workflow.js +27 -63
  180. package/dist/workflows/freeze/targets/command.js +2 -16
  181. package/dist/workflows/freeze/targets/shell.js +0 -2
  182. package/dist/workflows/freeze/task-bindings.js +2 -28
  183. package/dist/workflows/ir/params.js +12 -2
  184. package/dist/workflows/parser.js +82 -232
  185. package/dist/workflows/plan.js +1 -1
  186. package/dist/workflows/renderer.js +10 -19
  187. package/dist/workflows/runtime/run-plan.js +11 -53
  188. package/dist/workflows/runtime/runs.js +4 -27
  189. package/dist/workflows/source-files.js +12 -16
  190. package/dist/workflows/source-semantics.js +1 -93
  191. package/docs/README.md +1 -1
  192. package/docs/agents/README.md +3 -3
  193. package/docs/agents/agent-install.md +1 -1
  194. package/docs/architecture/0.10-process-rules.md +827 -0
  195. package/docs/architecture/adapters.md +17 -31
  196. package/docs/architecture/architecture.md +4 -5
  197. package/docs/architecture/improvement.md +115 -76
  198. package/docs/architecture/internals/improve-workflow.md +22 -16
  199. package/docs/architecture/internals/indexing.md +1 -1
  200. package/docs/architecture/internals/search.md +1 -2
  201. package/docs/architecture/internals/storage-locations.md +6 -6
  202. package/docs/architecture/persisted-data-compat.md +13 -4
  203. package/docs/architecture/specs/0.9.0-decisions.md +6 -2
  204. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
  205. package/docs/architecture/specs/workflow-format-unification.md +1 -6
  206. package/docs/architecture/testing/manual-testing-checklist.md +21 -30
  207. package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
  208. package/docs/architecture/testing/testing-workflow.md +1 -1
  209. package/docs/architecture/workflow-engine.md +5 -56
  210. package/docs/guides/author-workflows.md +39 -69
  211. package/docs/guides/bundles.md +3 -1
  212. package/docs/guides/capture-knowledge.md +1 -1
  213. package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
  214. package/docs/guides/discover-and-load.md +4 -4
  215. package/docs/guides/getting-started.md +1 -1
  216. package/docs/guides/improve-the-library.md +10 -9
  217. package/docs/guides/recipes/headless-install.md +2 -2
  218. package/docs/guides/run-workflows.md +1 -1
  219. package/docs/guides/scheduling.md +9 -1
  220. package/docs/guides/use-with-any-agent.md +49 -4
  221. package/docs/integration/bundling-akm.md +7 -6
  222. package/docs/maintainers/curate-workmap.md +1 -2
  223. package/docs/maintainers/release-checklist.md +33 -1
  224. package/docs/migration/README.md +2 -0
  225. package/docs/migration/release-notes/0.10.0.md +201 -0
  226. package/docs/migration/release-notes/README.md +1 -0
  227. package/docs/migration/v0.9-to-v0.10.md +507 -0
  228. package/docs/posts/akm-command-tour.md +3 -3
  229. package/docs/product-surface.md +1 -1
  230. package/docs/reference/README.md +1 -0
  231. package/docs/reference/api.md +65 -0
  232. package/docs/reference/asset-types.md +3 -5
  233. package/docs/reference/bundle-types.md +2 -4
  234. package/docs/reference/cli.md +160 -188
  235. package/docs/reference/configuration.md +101 -20
  236. package/docs/reference/data-and-telemetry.md +2 -2
  237. package/docs/reference/env-and-secrets.md +2 -2
  238. package/docs/reference/supported-formats.md +3 -4
  239. package/docs/reference/tasks.md +12 -19
  240. package/docs/reference/website-sources.md +1 -1
  241. package/docs/reference/workflow-schema.md +89 -317
  242. package/docs/reference/workflows.md +20 -48
  243. package/package.json +12 -2
  244. package/schemas/akm-config.json +2 -243
  245. package/schemas/akm-task.json +2 -3
  246. package/schemas/akm-workflow.json +47 -84
  247. package/dist/assets/improve-strategies/catchup.json +0 -41
  248. package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
  249. package/dist/assets/improve-strategies/quick.json +0 -17
  250. package/dist/assets/improve-strategies/reflect-distill.json +0 -29
  251. package/dist/assets/improve-strategies/thorough.json +0 -49
  252. package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
  253. package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
  254. package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
  255. package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
  256. package/dist/cli/retired-commands.js +0 -118
  257. package/dist/commands/improve/retrieval-gate.js +0 -132
  258. package/dist/commands/tasks/validate.js +0 -176
  259. package/dist/core/config/legacy-source-shape-shim.js +0 -117
  260. package/dist/indexer/feedback/utility-policy.js +0 -75
  261. package/dist/integrations/harnesses/ids.js +0 -28
  262. package/dist/tasks/source/task-source-v3-frozen.js +0 -424
  263. package/dist/tasks/source/task-to-v4.js +0 -863
  264. package/dist/workflows/exec/worktree.js +0 -372
  265. package/dist/workflows/freeze/child-output-references.js +0 -83
  266. package/dist/workflows/freeze/identity.js +0 -22
  267. package/dist/workflows/freeze/targets/script.js +0 -50
  268. package/dist/workflows/freeze/targets/task.js +0 -124
  269. package/dist/workflows/github-yaml.js +0 -506
  270. package/dist/workflows/runtime/run-outputs.js +0 -80
@@ -27,14 +27,9 @@ import { getParsedInvocation } from "../../cli/invocation.js";
27
27
  import { parsePositiveIntFlag } from "../../cli/parse-args.js";
28
28
  import { defineGroupCommand, defineJsonCommand, EXIT_CODES, GLOBAL_OUTPUT_ARGS, output, outputWithExitCode, runWithJsonErrors, } from "../../cli/shared.js";
29
29
  import { UsageError } from "../../core/errors.js";
30
- import { resolveUsageEventSource } from "../../indexer/usage/usage-events.js";
31
- import { getOutputMode } from "../../output/context.js";
32
30
  import { TASK_RUN_BOOLEAN_FLAGS, TASK_RUN_VALUE_FLAGS } from "../../tasks/task-run-reserved-flags.js";
33
- import { akmSearch, parseSearchSource } from "../read/search.js";
34
- import { rejectRetiredSourceFlag } from "../read/search-cli.js";
35
31
  import { akmTaskExplain } from "./explain.js";
36
32
  import { akmTasksAdd, akmTasksDisable, akmTasksDoctor, akmTasksEnable, akmTasksHistory, akmTasksPrune, akmTasksRun, akmTasksSync, akmTasksSyncPlan, } from "./tasks.js";
37
- import { akmTaskValidate } from "./validate.js";
38
33
  /** Shared `--bundle <bundle>` arg wired onto every task subcommand. */
39
34
  const bundleArg = {
40
35
  bundle: {
@@ -70,31 +65,6 @@ function hasFlagNamed(name) {
70
65
  }
71
66
  return false;
72
67
  }
73
- /**
74
- * `--target` was renamed to `--bundle` on `task` in 0.9 (S8.4). citty is
75
- * non-strict, so the retired spelling is silently absorbed rather than
76
- * rejected — reject it explicitly instead (mirrors improve-cli.ts /
77
- * remember-cli.ts). The generic pre-dispatch gate cannot catch it either: it
78
- * exempts `target` on every `task` subcommand precisely so this handler can
79
- * answer with the rename (`../../cli/unknown-flags`'s `SELF_DIAGNOSED_FLAGS`),
80
- * and that exemption is keyed on the flag NAME — so `--target=team` must be
81
- * rejected here by name too, or nothing rejects it at all.
82
- *
83
- * Rejecting by NAME means `--target=<value>` can no longer carry a declared
84
- * task input named `target` either (0.9.2 review round 2). That is settled on
85
- * the DECLARATION side, not by narrowing this rejecter back to whole-token
86
- * matching: `target` is listed in `TASK_RUN_SELF_DIAGNOSED_FLAGS`
87
- * (`../../tasks/task-run-reserved-flags.ts`), so `parseInputDeclarations`
88
- * refuses `inputs: {target: …}` with TASK_SOURCE_INVALID at authoring time and
89
- * no task can reach `akm task run` needing the flag this throws on. Do not
90
- * re-narrow the match here — the silently-ignored `--target=team` that round 1
91
- * closed would come straight back.
92
- */
93
- function rejectRetiredTaskTargetFlag() {
94
- if (!hasFlagNamed("target"))
95
- return;
96
- throw new UsageError("`akm task --target` was renamed to `--bundle` in 0.9. Use `--bundle <name>` instead.", "INVALID_FLAG_VALUE");
97
- }
98
68
  /**
99
69
  * `--scheduled` is `akm task run`'s own declared flag (an internal marker for
100
70
  * scheduler-generated runs) — `task explain` declares no such flag. Because
@@ -131,9 +101,7 @@ function rejectExplainScheduledFlag() {
131
101
  // that knows the task's declared contract (Stage 2, src/tasks/run/load-task.ts)
132
102
  // — coercion happens once, there. `akm task run`'s own declared flags
133
103
  // (GLOBAL_OUTPUT_ARGS, --bundle, --scheduled) are excluded so they are never
134
- // mistaken for inputs (B-33); `--target` is excluded too, but only because
135
- // `rejectRetiredTaskTargetFlag()` above always runs first and throws before
136
- // this is ever reached (B-32) — it is not itself special-cased below.
104
+ // mistaken for inputs (B-33).
137
105
  // `TASK_RUN_VALUE_FLAGS` / `TASK_RUN_BOOLEAN_FLAGS` are re-exported here
138
106
  // (unchanged in name, location, and value) from a dependency-free leaf module
139
107
  // so `src/tasks/source/task-source-v4.ts` can reject a declared `inputs:`
@@ -212,7 +180,7 @@ const tasksAddCommand = defineJsonCommand({
212
180
  },
213
181
  command: {
214
182
  type: "string",
215
- description: 'Exact shell string to run on the schedule (no AI agent), e.g. "akm improve --strategy reflect-distill".',
183
+ description: 'Exact shell string to run on the schedule (no AI agent), e.g. "akm improve --strategy consolidate".',
216
184
  },
217
185
  engine: { type: "string", description: "Engine to use for prompt targets (default: defaults.engine)" },
218
186
  model: { type: "string", description: "Model override for prompt targets" },
@@ -231,7 +199,6 @@ const tasksAddCommand = defineJsonCommand({
231
199
  },
232
200
  },
233
201
  async run({ args }) {
234
- rejectRetiredTaskTargetFlag();
235
202
  const result = await akmTasksAdd({
236
203
  id: args.id,
237
204
  schedule: args.schedule,
@@ -274,7 +241,6 @@ const tasksRunCommand = defineCommand({
274
241
  },
275
242
  async run({ args, rawArgs }) {
276
243
  await runWithJsonErrors(async () => {
277
- rejectRetiredTaskTargetFlag();
278
244
  const inputFlags = parseTaskInputFlags(rawArgs, args.id);
279
245
  const envelope = await akmTasksRun(args.id, {
280
246
  scheduled: args.scheduled === true,
@@ -299,7 +265,6 @@ const tasksEnableCommand = defineJsonCommand({
299
265
  ...bundleArg,
300
266
  },
301
267
  async run({ args }) {
302
- rejectRetiredTaskTargetFlag();
303
268
  output("task-enable", await akmTasksEnable(args.ref, { target: args.bundle }));
304
269
  },
305
270
  });
@@ -310,7 +275,6 @@ const tasksDisableCommand = defineJsonCommand({
310
275
  ...bundleArg,
311
276
  },
312
277
  async run({ args }) {
313
- rejectRetiredTaskTargetFlag();
314
278
  output("task-disable", await akmTasksDisable(args.ref, { target: args.bundle }));
315
279
  },
316
280
  });
@@ -336,7 +300,6 @@ const tasksHistoryCommand = defineJsonCommand({
336
300
  ...bundleArg,
337
301
  },
338
302
  async run({ args }) {
339
- rejectRetiredTaskTargetFlag();
340
303
  const limit = parsePositiveIntFlag(args.limit ?? undefined);
341
304
  const id = resolveTaskHistoryId(args.task, args.id);
342
305
  const result = await akmTasksHistory({ id, limit, target: args.bundle });
@@ -376,7 +339,6 @@ const tasksSyncCommand = defineJsonCommand({
376
339
  },
377
340
  },
378
341
  async run({ args }) {
379
- rejectRetiredTaskTargetFlag();
380
342
  const rebind = args.rebind === true;
381
343
  if (args["dry-run"] === true) {
382
344
  const preview = await akmTasksSyncPlan({}, args.bundle, { rebind });
@@ -405,7 +367,6 @@ const tasksExplainCommand = defineJsonCommand({
405
367
  ...bundleArg,
406
368
  },
407
369
  async run({ args, rawArgs }) {
408
- rejectRetiredTaskTargetFlag();
409
370
  // `--scheduled` must be rejected BEFORE the shared scanner below ever
410
371
  // sees it — the scanner treats it as `task run`'s own reserved flag
411
372
  // (silently skipped, never surfaced as unknown) rather than explain's,
@@ -434,35 +395,6 @@ const tasksDoctorCommand = defineJsonCommand({
434
395
  output("task-doctor", result);
435
396
  },
436
397
  });
437
- /**
438
- * #907: `akm task validate`'s exit-code contract — `valid` succeeds (exit
439
- * 0); `blocked`/`invalid`/`not-a-task` are diagnosed defects the caller must
440
- * act on (exit 1, mirroring `task sync`'s own `failures.length > 0 ->
441
- * EXIT_CODES.GENERAL`). A missing path or an unreadable file never reaches
442
- * this function at all — `akmTaskValidate` throws a `UsageError` for those,
443
- * which `defineJsonCommand`'s wrapping already maps to exit 2.
444
- */
445
- export function taskValidateExitCode(result) {
446
- return result.outcome === "valid" ? undefined : EXIT_CODES.GENERAL;
447
- }
448
- const tasksValidateCommand = defineJsonCommand({
449
- meta: {
450
- name: "validate",
451
- description: "Parse a single task file by filesystem path — not a concept ref, and the file need not live in a " +
452
- "configured bundle — and report the same diagnostic `akm task sync` would produce for it. Read-only; " +
453
- "never touches the scheduler.",
454
- },
455
- args: {
456
- path: { type: "positional", description: "Filesystem path to a task source YAML file", required: true },
457
- },
458
- async run({ args }) {
459
- const result = await akmTaskValidate(args.path);
460
- output("task-validate", result);
461
- const exitCode = taskValidateExitCode(result);
462
- if (exitCode !== undefined)
463
- process.exitCode = exitCode;
464
- },
465
- });
466
398
  /**
467
399
  * #851: `akm task prune`'s exit-code contract mirrors `task sync --dry-run`'s
468
400
  * (`taskSyncDryRunExitCode` above) — non-zero whenever the preview lists
@@ -503,47 +435,6 @@ const tasksPruneCommand = defineJsonCommand({
503
435
  outputWithExitCode("task-prune", result, taskPruneExitCode(result));
504
436
  },
505
437
  });
506
- /**
507
- * #951: `akm task list` — a pure, zero-logic delegating alias for
508
- * `akm search --type task`. 0.9.0 removed `task list` because it was a
509
- * second, redundant IMPLEMENTATION of task listing, not because the
510
- * spelling itself was off-limits; this reuses `search`'s exact envelope
511
- * (its `results` alias comes along for free) instead of adding a second one.
512
- * `query`/`--limit`/`--from` are handled identically to `searchCommand.run()`
513
- * for the same inputs, including the retired `--source` guard (`../read/
514
- * search-cli.ts`'s `rejectRetiredSourceFlag`, reused rather than copied) so
515
- * `akm task list --source x` fails with the same actionable rename message
516
- * as `akm search --type task --source x` instead of citty's silent absorb.
517
- */
518
- const tasksListCommand = defineJsonCommand({
519
- meta: { name: "list", description: "List task assets (alias for `akm search --type task`)" },
520
- args: {
521
- query: {
522
- type: "positional",
523
- description: "Search query (omit to list all tasks)",
524
- required: false,
525
- default: "",
526
- },
527
- limit: { type: "string", description: "Maximum number of results" },
528
- from: { type: "string", description: "Search source (local|registry|all)", default: "local" },
529
- },
530
- async run({ args }) {
531
- rejectRetiredSourceFlag();
532
- const query = (args.query ?? "").trim();
533
- const limit = parsePositiveIntFlag(args.limit ?? undefined);
534
- const source = parseSearchSource(args.from);
535
- const outputMode = getOutputMode();
536
- const result = await akmSearch({
537
- query,
538
- type: "task",
539
- limit,
540
- source,
541
- eventSource: resolveUsageEventSource(),
542
- attributionProjection: outputMode.shape === "agent" ? "agent" : outputMode.detail,
543
- });
544
- output("search", result);
545
- },
546
- });
547
438
  export const taskCommand = defineGroupCommand({
548
439
  meta: {
549
440
  name: "task",
@@ -555,16 +446,14 @@ export const taskCommand = defineGroupCommand({
555
446
  disable: tasksDisableCommand,
556
447
  run: tasksRunCommand,
557
448
  explain: tasksExplainCommand,
558
- validate: tasksValidateCommand,
559
449
  history: tasksHistoryCommand,
560
- list: tasksListCommand,
561
450
  sync: tasksSyncCommand,
562
451
  prune: tasksPruneCommand,
563
452
  doctor: tasksDoctorCommand,
564
453
  },
565
454
  // Bare `akm task` reports scheduler diagnostics. Deeper inspection of
566
- // individual tasks is the generic `akm show <bundle//tasks/id>`; `list`
567
- // above is a delegating alias for `akm search --type task` (#951).
455
+ // individual tasks is the generic `akm show <bundle//tasks/id>`; listing is
456
+ // `akm search --type task`.
568
457
  // No `defaultRun`: bare `akm task` is a usage error (exit 2), the canonical
569
458
  // bare-group behavior — owner ruling 12. Run `akm task doctor` for what the
570
459
  // bare form used to run.
@@ -16,13 +16,12 @@
16
16
  * `request.persona`, `request.conversation`, `request.runtime.environment`,
17
17
  * and a script target's `bytesBase64` are never read at all.
18
18
  */
19
- import path from "node:path";
20
19
  import { loadConfig } from "../../core/config/config.js";
21
20
  import { buildExecutionFromWire } from "../../integrations/agent/execution.js";
22
21
  import { freezeWorkflow } from "../../workflows/freeze/freeze.js";
23
22
  import { computePlanHash } from "../../workflows/ir/plan-hash.js";
24
23
  import { loadWorkflowAsset } from "../../workflows/runtime/workflow-asset-loader.js";
25
- /** The step's dispatch unit — the map template for a fan-out, else the root unit. Undefined for a route step. */
24
+ /** The step's dispatch unit — the map template for a fan-out, else the root unit. Undefined for a step not yet frozen. */
26
25
  function stepUnit(step) {
27
26
  const root = step.root;
28
27
  if (!root)
@@ -41,41 +40,23 @@ function projectInputBinding(binding) {
41
40
  ? { name: binding.name, kind: "literal", value: binding.value }
42
41
  : { name: binding.name, kind: "reference", from: binding.from };
43
42
  }
44
- function childExportedOutputNames(frozenPlan) {
45
- return frozenPlan.outputs ? Object.keys(frozenPlan.outputs) : ["runId", "status"];
46
- }
47
- /**
48
- * A `child-workflow` target's `expansion`. Recurses into the embedded
49
- * plan's own steps in the identical shape — `usesById` is
50
- * omitted for the recursive call because a nested child's own authored
51
- * source is not available here (only its already-frozen plan is), so a
52
- * task-wrapped step nested inside a child conservatively reports `via:
53
- * "direct"` rather than guessing at its authoring surface.
54
- */
43
+ /** A `child-workflow` target's `expansion`. Recurses into the embedded plan's own steps in the identical shape. */
55
44
  function childExpansion(target) {
56
45
  return {
57
46
  via: "child",
58
47
  childRef: target.ref,
59
48
  childPlanHash: target.planHash,
60
- childVia: target.via,
61
- ...(target.taskRef !== undefined ? { childTaskRef: target.taskRef } : {}),
62
- childOutputs: childExportedOutputNames(target.frozenPlan),
63
- steps: target.frozenPlan.steps.map((step, index) => projectStep(step, index, undefined)),
49
+ steps: target.frozenPlan.steps.map((step, index) => projectStep(step, index)),
64
50
  };
65
51
  }
66
- /** The task/child expansion boundary for one step (§4.6). */
67
- function stepExpansion(step, frozenTarget, usesById) {
68
- if (frozenTarget?.kind === "child-workflow")
69
- return childExpansion(frozenTarget);
70
- const uses = usesById?.get(step.stepId);
71
- if (uses?.startsWith("tasks/"))
72
- return { via: "task", taskRef: uses };
73
- return { via: "direct" };
52
+ /** The child expansion boundary for one step (§4.6). */
53
+ function stepExpansion(frozenTarget) {
54
+ return frozenTarget?.kind === "child-workflow" ? childExpansion(frozenTarget) : { via: "direct" };
74
55
  }
75
- function projectStep(step, sequenceIndex, usesById) {
56
+ function projectStep(step, sequenceIndex) {
76
57
  const unit = stepUnit(step);
77
58
  const frozenTarget = unit?.frozenTarget;
78
- const kind = step.route ? "route" : step.root?.kind === "map" ? "map" : "unit";
59
+ const kind = step.root?.kind === "map" ? "map" : "unit";
79
60
  const inputBindings = frozenTarget?.inputBindings;
80
61
  return {
81
62
  stepId: step.stepId,
@@ -92,7 +73,7 @@ function projectStep(step, sequenceIndex, usesById) {
92
73
  judgeEngine: step.gate.frozenJudge ? step.gate.frozenJudge.request.engine.name : null,
93
74
  },
94
75
  ...(step.outputSchema !== undefined ? { outputSchema: step.outputSchema } : {}),
95
- expansion: stepExpansion(step, frozenTarget, usesById),
76
+ expansion: stepExpansion(frozenTarget),
96
77
  };
97
78
  }
98
79
  /**
@@ -130,13 +111,11 @@ export async function akmWorkflowPlan(ref) {
130
111
  const config = loadConfig();
131
112
  const frozen = await freezeWorkflow(asset, config);
132
113
  const plan = frozen.plan;
133
- const usesById = new Map(asset.plan.steps.map((step) => [step.stepId, step.spec?.uses]));
134
- const sourceFormat = path.extname(asset.path).toLowerCase() === ".md" ? "markdown" : "github-yaml";
135
114
  return {
136
115
  ok: true,
137
116
  ref: asset.ref,
138
117
  title: asset.title,
139
- sourceFormat,
118
+ sourceFormat: "markdown",
140
119
  sourcePath: asset.path,
141
120
  irVersion: plan.irVersion,
142
121
  planHash: computePlanHash(plan),
@@ -144,8 +123,7 @@ export async function akmWorkflowPlan(ref) {
144
123
  execution: plan.execution,
145
124
  ...(plan.budget ? { budget: plan.budget } : {}),
146
125
  ...(plan.params ? { params: plan.params } : {}),
147
- ...(plan.outputs ? { outputs: plan.outputs } : {}),
148
- steps: plan.steps.map((step, index) => projectStep(step, index, usesById)),
126
+ steps: plan.steps.map((step, index) => projectStep(step, index)),
149
127
  notices: collectLoweringNotices(plan, config),
150
128
  warnings: frozen.warnings.map((warning) => warning.message),
151
129
  };
@@ -4,8 +4,8 @@
4
4
  /**
5
5
  * `akm workflow` command family. `run` is the canonical start/resume/execute
6
6
  * surface; the former public `start`, `next`, and `complete` lifecycle is gone.
7
- * `create --print` emits Markdown; execution accepts peer `.md` and
8
- * GitHub-shaped `.yml` workflow sources. Validate with `akm lint --type workflows`.
7
+ * `create --print` emits Markdown, the only workflow source format. Validate
8
+ * with `akm lint --type workflows`.
9
9
  */
10
10
  import { getStringArg } from "../cli/parse-args.js";
11
11
  import { defineGroupCommand, defineJsonCommand, EXIT_CODES, output, outputWithExitCode } from "../cli/shared.js";
@@ -129,11 +129,6 @@ const workflowCreateCommand = defineJsonCommand({
129
129
  description: "Overwrite an existing workflow. Combined with --from, replaces its content; alone, replaces it with a fresh template.",
130
130
  default: false,
131
131
  },
132
- reset: {
133
- type: "boolean",
134
- description: "Deprecated alias for --force with no --from (replaces an existing workflow with a fresh template).",
135
- default: false,
136
- },
137
132
  print: {
138
133
  type: "boolean",
139
134
  description: "Print the RAW template that would be written to stdout without creating anything — pipe it to a file as a starter document",
@@ -2,8 +2,7 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * Dependency-free adapter-id table (#909) — mirrors
6
- * `src/integrations/harnesses/ids.ts`'s split from its own heavy barrel.
5
+ * Dependency-free adapter-id table (#909).
7
6
  *
8
7
  * `core/config/schema/sources-bundles.ts` needs one small, DATA-shaped fact
9
8
  * about the adapter registry: the canonical ordered id list, to validate
@@ -231,10 +231,6 @@ export const agentSkillsAdapter = {
231
231
  readCandidates(c, conceptId) {
232
232
  return [{ path: path.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
233
233
  },
234
- /** A skill places to `<name>/SKILL.md`; the conceptId IS the package directory (spec §4.5). */
235
- placeNew(c, conceptId) {
236
- return path.join(c.root, conceptId, SKILL_MANIFEST);
237
- },
238
234
  /** Install-time probe (§1.2): a root that directly contains one or more `<name>/SKILL.md` skill packages. */
239
235
  looksLikeRoot(root) {
240
236
  let entries;
@@ -39,23 +39,22 @@
39
39
  * conceptId = `<stash-subdir>/<canonical-name>` — the placement stash-subdir
40
40
  * (`stashDirFor(type)`) followed by the winning type's canonical name
41
41
  * (`deriveCanonicalAssetNameFromStashRoot`: skill = its dir, script keeps its
42
- * extension, Markdown strips `.md`, workflow strips its peer `.md`/`.yml`
42
+ * extension, Markdown strips `.md`, workflow strips its `.md`
43
43
  * extension, env/task strip their ext, and secret/session keep the natural
44
44
  * path). For Markdown types this IS the OKF concept ID (path − `.md`); it is
45
- * the same spelling {@link placeNew} consumes, so
46
- * recognize/place share one identity (D-R2 resolved the earlier split). The
45
+ * the same spelling `readCandidates` consumes, so
46
+ * recognize/read share one identity (D-R2 resolved the earlier split). The
47
47
  * `type` is carried separately on `IndexDocument.type`, per §0.2 (type ≠
48
48
  * identity), and `entry.name` keeps the BARE canonical name for FTS parity.
49
49
  *
50
- * ── placeNew / directoryList / looksLikeRoot: type-driven placement ──
50
+ * ── readCandidates / directoryList / looksLikeRoot: type-driven placement ──
51
51
  *
52
52
  * Placement is type-driven (`path-resolver.ts#buildDiskCandidates`: the primary
53
53
  * candidate is `assetPathForName(ref.type, join(root, stashDirFor(ref.type)),
54
- * ref.name)`). §5.1 removes `type` from the ref, so {@link placeNew} recovers
54
+ * ref.name)`). §5.1 removes `type` from the ref, so `readCandidates` recovers
55
55
  * it from the conceptId's LEADING path segment — the qualified `<stash-subdir>/
56
56
  * <name>` form of §1.3 — reverse-mapping that segment against the placement
57
- * stash-subdir map and then delegating to `assetPathForName`. See the method
58
- * doc for the recognize/place conceptId-spelling note.
57
+ * stash-subdir map and then delegating to `assetPathCandidatesForName`.
59
58
  *
60
59
  * ── validate: base checks only (WI-B) ──
61
60
  *
@@ -82,11 +81,11 @@
82
81
  import fs from "node:fs";
83
82
  import path from "node:path";
84
83
  import { applyPostContributorFields, applyPreContributorFields, extractPackageMetadata, getMarkdownFragmentContent, hasMarkdownFragmentContent, setMarkdownFragmentContent, } from "../../../indexer/passes/metadata.js";
85
- import { assetPathCandidatesForName, assetPathForName, deriveCanonicalAssetNameFromStashRoot, placementTypes, stashDirFor, stashDirNames, } from "../../asset/asset-placement.js";
84
+ import { assetPathCandidatesForName, deriveCanonicalAssetNameFromStashRoot, placementTypes, stashDirFor, stashDirNames, } from "../../asset/asset-placement.js";
86
85
  import { parseFrontmatter } from "../../asset/frontmatter.js";
87
86
  import { executionDefaultsFromFrontmatter, renderMarkdownExecutionSource } from "../execution-source.js";
88
87
  import { recognizeMatch } from "../recognize-match.js";
89
- import { perTypeValidateChecks, skillDirectoryDiagnostics, workflowYamlSourceDiagnostics } from "./akm-lint.js";
88
+ import { perTypeValidateChecks, skillDirectoryDiagnostics } from "./akm-lint.js";
90
89
  import { applyFoldedMetadata, foldRecognizedMetadata } from "./akm-metadata.js";
91
90
  import { hashContent, RESERVED_FILES, runBaseValidateChecks } from "./shared.js";
92
91
  // `recognizeMatch` + the builtin matcher list moved to the cycle-free leaf
@@ -285,7 +284,7 @@ function recognize(c, file) {
285
284
  const stashDir = stashDirFor(match.type);
286
285
  const canonicalName = stashDir !== undefined ? conceptId.slice(stashDir.length + 1) : conceptId;
287
286
  // conceptId = the QUALIFIED `<stash-subdir>/<canonical-name>` spelling
288
- // (ref-grammar decision D-R2): the same form `placeNew` consumes; Markdown
287
+ // (ref-grammar decision D-R2): the same form `readCandidates` consumes; Markdown
289
288
  // types use the OKF concept ID (path − .md), while workflows strip either
290
289
  // peer source extension. Both branches feed a
291
290
  // BARE canonicalName (the abstain fallback is the basename, above), so the
@@ -419,12 +418,6 @@ async function validate(c, changes, ctx) {
419
418
  const overlay = buildOverlayContext(c.root, change.path, raw);
420
419
  const match = recognizeMatch(overlay);
421
420
  const type = match?.type;
422
- // A complete GitHub-shaped `on` + `jobs` document is workflow-owned. It
423
- // never flows through task-v3 parsing or Markdown base/frontmatter checks.
424
- if (type === "workflow" && overlay.ext === ".yml") {
425
- diagnostics.push(...workflowYamlSourceDiagnostics(change.path, raw, change.path, c.root).errors);
426
- continue;
427
- }
428
421
  // Task parsing belongs to perTypeValidateChecks' canonical v3 parser. Base
429
422
  // checks need only a frontmatter-free placeholder here.
430
423
  let parsed;
@@ -519,38 +512,6 @@ export const akmAdapter = {
519
512
  conceptId: posix,
520
513
  }));
521
514
  },
522
- /**
523
- * Type-driven placement (§5.1), reproducing `path-resolver.ts#buildDiskCandidates`:
524
- * the primary candidate is
525
- * `assetPathForName(type, join(root, stashDirFor(type)), name)`.
526
- *
527
- * §5.1 removes `type` from the ref, so the winning type is recovered from the
528
- * conceptId's LEADING path segment — the §1.3 qualified `<stash-subdir>/<name>`
529
- * form (e.g. `knowledge/http-caching`, `workflows/release`, `skills/<dir>`).
530
- * The leading segment is reverse-mapped against the placement stash-subdir map;
531
- * the remainder is the per-type name handed to `assetPathForName`. An
532
- * unqualified conceptId (no recognized leading stash-subdir) falls back to a
533
- * direct `<root>/<conceptId>.md` — the same `${name}.md` fallback
534
- * `buildDiskCandidates` carries (`preserveDirectNameFallback`).
535
- *
536
- * `recognize()` emits the SAME qualified spelling (ref-grammar decision
537
- * D-R2), so recognize/place share one canonical identity — the earlier
538
- * bare-vs-qualified split is resolved.
539
- */
540
- placeNew(c, conceptId) {
541
- const posix = conceptId.replace(/\\/g, "/");
542
- const slash = posix.indexOf("/");
543
- if (slash > 0) {
544
- const head = posix.slice(0, slash);
545
- const rest = posix.slice(slash + 1);
546
- const type = stashDirToType(head);
547
- if (type !== undefined && rest.length > 0) {
548
- const typeDir = path.join(c.root, head);
549
- return assetPathForName(type, typeDir, rest);
550
- }
551
- }
552
- return path.join(c.root, `${posix}.md`);
553
- },
554
515
  /** The AKM workspace's owned stash subdirs (§7): the placement stash-subdir names, feeding git exact-path staging. */
555
516
  directoryList(_c) {
556
517
  return [...new Set(stashDirNames())];
@@ -52,6 +52,8 @@
52
52
  */
53
53
  import path from "node:path";
54
54
  import { isDangerousEnvKey } from "../../../commands/lint/env-key-rules.js";
55
+ import { backendNameForPlatform } from "../../../tasks/backends/index.js";
56
+ import { assertTaskScheduleCronValid, assertTaskScheduleInputsSatisfyContract } from "../../../tasks/schedule-gates.js";
55
57
  import { parseTaskSource } from "../../../tasks/source/parse-task-source.js";
56
58
  import { taskSourceErrorDetail } from "../../../tasks/source-v3.js";
57
59
  import { checkWorkflowPlan, compileWorkflowSource } from "../../../workflows/compile.js";
@@ -216,7 +218,6 @@ export async function perTypeValidateChecks(args) {
216
218
  case "task":
217
219
  return taskDiagnostics(relPath, raw, workspaceRoot);
218
220
  case "workflow":
219
- // Markdown lint handles `.md`; peer GitHub-shaped `.yml` sources enter through the workflow source adapter.
220
221
  return ext === ".md" ? workflowDiagnostics(relPath, raw, body) : [];
221
222
  case "memory":
222
223
  return memoryDiagnostics(relPath, data, body, ctx);
@@ -259,14 +260,21 @@ export function factDiagnostics(relPath, data) {
259
260
  * through the strict task-v3 grammar, `version: 4` through task source v4.
260
261
  * Keeping raw YAML at this boundary preserves duplicate-key, alias/tag,
261
262
  * source-location, descriptor, resource-bound, and migration-hint behavior.
263
+ *
264
+ * A file that parses must also pass the two per-source gates `akm task sync`
265
+ * runs before it installs a schedule (the schedule inputs satisfy the declared
266
+ * contract; the cron suits the local scheduler backend), so `akm lint --type
267
+ * tasks` never reports clean a task that sync would refuse.
262
268
  */
263
269
  export function taskDiagnostics(relPath, raw, workspaceRoot) {
264
270
  try {
265
- parseTaskSource({
271
+ const parsed = parseTaskSource({
266
272
  filePath: relPath,
267
273
  yaml: raw,
268
274
  ...(workspaceRoot ? { workspaceRoot } : {}),
269
275
  });
276
+ assertTaskScheduleInputsSatisfyContract(parsed.v4, relPath);
277
+ assertTaskScheduleCronValid(parsed.v4, backendNameForPlatform());
270
278
  return [];
271
279
  }
272
280
  catch (cause) {
@@ -310,30 +318,6 @@ export function workflowStructureDiagnostics(relPath, raw, parsePath) {
310
318
  function lineOf(err) {
311
319
  return typeof err.line === "number" && Number.isFinite(err.line) && err.line > 0 ? { line: err.line } : {};
312
320
  }
313
- /**
314
- * Compile one peer GitHub-shaped `.yml` source through the shared source-IR
315
- * frontend. YAML has no Markdown frontmatter/base/stub pass and currently
316
- * emits fatal source diagnostics only; keeping the same two-channel result
317
- * shape lets the ordinary sweep and both workflow adapters route it exactly
318
- * like the established Markdown frontend without inventing another parser.
319
- */
320
- export function workflowYamlSourceDiagnostics(relPath, raw, parsePath, workspaceRoot) {
321
- if (isAkmRegistryCachePath(parsePath))
322
- return { errors: [], warnings: [] };
323
- const compiled = compileWorkflowSource(raw, { path: parsePath, workspaceRoot });
324
- if (compiled.ok)
325
- return { errors: [], warnings: [] };
326
- return {
327
- errors: compiled.errors.map((error) => ({
328
- file: relPath,
329
- issue: "invalid-workflow-structure",
330
- detail: error.message,
331
- fixed: false,
332
- ...lineOf(error),
333
- })),
334
- warnings: [],
335
- };
336
- }
337
321
  /**
338
322
  * ONE parse+compile of a workflow through the unified frontend, returning both
339
323
  * halves of what it produces: fatal `invalid-workflow-structure` findings, and
@@ -1,60 +1,6 @@
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
- * Index-time metadata fold for the `akm` adapter's `recognize` — akm 0.9.0
6
- * chunk-2, WI-C, implementing spec §2 ("the nine index-time metadata
7
- * contributors move into recognize") + the workflow contributor.
8
- *
9
- * This leaf reproduces the 11 `registerMetadataContributor` sites keyed on the
10
- * winning RENDERER name (exactly how each contributor's `appliesTo({ rendererName })`
11
- * selects):
12
- *
13
- * - `output/renderers.ts` (9): toc-metadata (knowledge-md),
14
- * lesson-frontmatter-metadata, memory-frontmatter-metadata,
15
- * script-comment-metadata, env-file-metadata, secret-file-metadata,
16
- * task-yaml-metadata, session-md-metadata, fact-md-metadata;
17
- * - `workflows/renderer.ts` (1): workflow-document-metadata (the historical
18
- * `workflow-md` renderer id now presents both peer workflow sources).
19
- *
20
- * ── Cycle-safety (chunk-2 ratchet, baseline 18) ──
21
- *
22
- * Imported ONLY by `akm-adapter.ts` (itself imported by nothing in `src/` — see
23
- * that file's header), so this leaf can never gain an inbound edge from a cycle
24
- * participant and therefore can never JOIN a cycle. It VALUE-imports the pure
25
- * parsers each contributor already uses so the fold cannot drift from them:
26
- * `parseFrontmatter`, `parseMarkdownToc`, the peer-source
27
- * `compileWorkflowSource` frontend/projection, and env key-name scanning.
28
- * `output/renderers.ts` / `workflows/renderer.ts` are the
29
- * cycle-sensitive modules whose contributor bodies live in this port — their
30
- * ONE non-importable helper (`metadata.ts#extractDescriptionFromComments`, a
31
- * heavy cycle-participant module) is copied verbatim below as
32
- * {@link extractDescriptionFromComments} rather than imported. Verified:
33
- * `bun scripts/lint-import-cycles.ts` stays at 18.
34
- *
35
- * ── What is folded, and where it lands on the IndexDocument ──
36
- *
37
- * The contributors mutate a `IndexDocument`; {@link foldRecognizedMetadata} returns
38
- * the same fields as a plain {@link FoldedMetadata}, which `recognize` maps onto
39
- * `IndexDocument` first-class fields (`tags`/`searchHints`/`description`/
40
- * `confidence`) and, for the fields without a first-class home
41
- * (`toc`/`parameters`/`source`), onto `documentJson` (opaque adapter extras).
42
- * The seed is a MINIMAL entry (name+type only): this isolates exactly what the
43
- * contributors add, which is what the parity test compares against
44
- * `applyMetadataContributors` run on the same minimal seed.
45
- *
46
- * ── Tolerance note ──
47
- *
48
- * Every contributor that reads/parses content is reproduced with the SAME
49
- * try/catch tolerance it has today (toc/memory/session/fact/task swallow parse
50
- * errors). Workflow source compilation fails closed in the drain (a broken
51
- * workflow is dropped); here the compile/projection is wrapped
52
- * so a broken workflow yields no folded metadata instead of throwing out of the
53
- * synchronous `recognize` — the drop-the-entry behavior is an index-drain
54
- * concern (Chunk 4/5), not recognition's. On the valid Chunk-0b fixture this
55
- * distinction never triggers.
56
- */
57
- import { parseBuiltinCommandAction } from "../../../commands/command/builtin-action.js";
58
4
  import { scanEnvKeyNames } from "../../../commands/env/env.js";
59
5
  import { parseTaskSource } from "../../../tasks/source/parse-task-source.js";
60
6
  import { compileWorkflowSource, workflowStepInstructions } from "../../../workflows/compile.js";
@@ -130,21 +76,6 @@ function applyFrontmatterDescriptionAndTags(fm, out) {
130
76
  function storedCommandRef(action) {
131
77
  return action?.kind === "stored" ? action.ref : undefined;
132
78
  }
133
- /** The asset a workflow step targets: its `uses:` ref, or the ref of a stored `akm/command`. Prose and `run:` steps target none. */
134
- function workflowStepTarget(spec) {
135
- if (!spec?.uses)
136
- return undefined;
137
- if (spec.uses !== "akm/command")
138
- return spec.uses;
139
- if (spec.commandMode !== "stored-ref")
140
- return undefined;
141
- try {
142
- return storedCommandRef(parseBuiltinCommandAction(spec.with));
143
- }
144
- catch {
145
- return undefined;
146
- }
147
- }
148
79
  /** Collect + finalize a searchHints set the way every contributor does (`Array.from(hints).filter(Boolean)`, assigned only when non-empty). */
149
80
  function finalizeHints(out, hints) {
150
81
  if (hints.size > 0)
@@ -352,9 +283,8 @@ export function foldRecognizedMetadata(rendererName, file) {
352
283
  hints.add(workflowStepInstructions(step));
353
284
  if (step.gate.criteria[0])
354
285
  hints.add(step.gate.criteria[0]);
355
- const used = workflowStepTarget(step.spec);
356
- if (used)
357
- uses.add(used);
286
+ if (step.spec?.workflow)
287
+ uses.add(step.spec.workflow);
358
288
  }
359
289
  out.searchHints = Array.from(hints).filter(Boolean);
360
290
  if (uses.size > 0)
@@ -114,11 +114,6 @@ export const akmTaskAdapter = {
114
114
  { path: path.join(c.root, `${posix}.yaml`), conceptId: posix },
115
115
  ];
116
116
  },
117
- /** A task places to `<conceptId>.yml`; an already-suffixed conceptId is idempotent. */
118
- placeNew(c, conceptId) {
119
- const posix = toPosix(conceptId);
120
- return path.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
121
- },
122
117
  /** Tasks live anywhere under the component root. */
123
118
  directoryList() {
124
119
  return ["."];