akm-cli 0.9.31 → 0.10.26101002-alpha

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 (236) hide show
  1. package/CHANGELOG.md +265 -0
  2. package/STABILITY.md +79 -53
  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 +13 -27
  7. package/dist/assets/hints/cli-hints-short.md +1 -1
  8. package/dist/assets/improve-strategies/default.json +3 -3
  9. package/dist/assets/prompts/consolidate-pair.md +9 -7
  10. package/dist/cli/shared.js +31 -48
  11. package/dist/cli/unknown-flags.js +6 -43
  12. package/dist/cli.js +8 -34
  13. package/dist/commands/agent/contribute-cli.js +1 -1
  14. package/dist/commands/completions.js +1 -2
  15. package/dist/commands/config-cli.js +5 -28
  16. package/dist/commands/env/env-cli.js +5 -5
  17. package/dist/commands/env/secret-cli.js +2 -2
  18. package/dist/commands/health/checks.js +41 -16
  19. package/dist/commands/health/plugin-staleness.js +52 -22
  20. package/dist/commands/improve/autonomy-gate.js +5 -3
  21. package/dist/commands/improve/consolidate/pair-pass.js +7 -1
  22. package/dist/commands/improve/consolidate.js +6 -35
  23. package/dist/commands/improve/distill/lesson-update.js +91 -0
  24. package/dist/commands/improve/distill-guards.js +1 -43
  25. package/dist/commands/improve/distill.js +140 -20
  26. package/dist/commands/improve/eligibility.js +14 -1
  27. package/dist/commands/improve/extract-cli.js +1 -1
  28. package/dist/commands/improve/improve-cli.js +87 -102
  29. package/dist/commands/improve/improve-strategies.js +8 -12
  30. package/dist/commands/improve/improve.js +2 -2
  31. package/dist/commands/improve/loop-stages.js +0 -1
  32. package/dist/commands/improve/planner.js +0 -1
  33. package/dist/commands/improve/preparation.js +40 -99
  34. package/dist/commands/improve/proactive-maintenance.js +2 -2
  35. package/dist/commands/improve/reflect-noise.js +3 -55
  36. package/dist/commands/improve/reflect.js +3 -8
  37. package/dist/commands/improve/retrieval-scope.js +2 -2
  38. package/dist/commands/improve/salience.js +2 -9
  39. package/dist/commands/improve/stage.js +14 -9
  40. package/dist/commands/lint/index.js +5 -20
  41. package/dist/commands/observability-cli.js +3 -9
  42. package/dist/commands/proposal/drain.js +39 -6
  43. package/dist/commands/proposal/proposal-cli.js +11 -31
  44. package/dist/commands/proposal/repository.js +3 -3
  45. package/dist/commands/read/knowledge.js +3 -3
  46. package/dist/commands/read/remember-cli.js +0 -13
  47. package/dist/commands/read/search-cli.js +29 -97
  48. package/dist/commands/read/search.js +0 -11
  49. package/dist/commands/read/show.js +0 -19
  50. package/dist/commands/sources/plugin-upgrade.js +164 -101
  51. package/dist/commands/sources/sources-cli.js +1 -15
  52. package/dist/commands/sources/stash-cli.js +4 -12
  53. package/dist/commands/tasks/tasks-cli.js +4 -115
  54. package/dist/commands/workflow/plan.js +11 -33
  55. package/dist/commands/workflow-cli.js +2 -7
  56. package/dist/core/adapter/adapter-ids.js +1 -2
  57. package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
  58. package/dist/core/adapter/adapters/akm-adapter.js +9 -48
  59. package/dist/core/adapter/adapters/akm-lint.js +10 -26
  60. package/dist/core/adapter/adapters/akm-metadata.js +2 -72
  61. package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
  62. package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
  63. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
  64. package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
  65. package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
  66. package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
  67. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
  68. package/dist/core/adapter/recognize-match.js +3 -4
  69. package/dist/core/common.js +18 -2
  70. package/dist/core/config/config-schema.js +12 -15
  71. package/dist/core/config/config-types.js +6 -15
  72. package/dist/core/config/config-walker.js +6 -23
  73. package/dist/core/config/config.js +17 -80
  74. package/dist/core/config/engine-semantics.js +7 -3
  75. package/dist/core/config/schema/engines.js +7 -7
  76. package/dist/core/config/schema/improve-processes.js +8 -61
  77. package/dist/core/config/schema/improve.js +2 -21
  78. package/dist/core/config/schema/index-config.js +6 -39
  79. package/dist/core/env-secret-ref.js +2 -45
  80. package/dist/core/errors.js +1 -2
  81. package/dist/core/extra-params.js +2 -86
  82. package/dist/core/improve-result.js +11 -1
  83. package/dist/core/mutation-target.js +2 -2
  84. package/dist/core/recognition-util.js +4 -5
  85. package/dist/core/warn.js +21 -4
  86. package/dist/core/write-source.js +3 -3
  87. package/dist/execution/target-ref.js +1 -2
  88. package/dist/indexer/search/db-search.js +4 -19
  89. package/dist/indexer/search/fts-query.js +0 -19
  90. package/dist/integrations/agent/engine-resolution.js +5 -2
  91. package/dist/integrations/agent/index.js +1 -1
  92. package/dist/integrations/agent/profiles.js +41 -98
  93. package/dist/integrations/agent/request-lowering.js +3 -3
  94. package/dist/integrations/harnesses/aider/index.js +5 -0
  95. package/dist/integrations/harnesses/amazonq/index.js +1 -0
  96. package/dist/integrations/harnesses/claude/config-import.js +2 -3
  97. package/dist/integrations/harnesses/claude/index.js +5 -0
  98. package/dist/integrations/harnesses/codex/index.js +1 -0
  99. package/dist/integrations/harnesses/copilot/index.js +1 -0
  100. package/dist/integrations/harnesses/gemini/index.js +1 -0
  101. package/dist/integrations/harnesses/index.js +18 -39
  102. package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
  103. package/dist/integrations/harnesses/opencode/config-import.js +121 -52
  104. package/dist/integrations/harnesses/opencode/index.js +22 -0
  105. package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
  106. package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
  107. package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
  108. package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
  109. package/dist/integrations/harnesses/opencode/session-log.js +104 -115
  110. package/dist/integrations/harnesses/opencode/version.js +98 -0
  111. package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
  112. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
  113. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
  114. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +228 -0
  115. package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
  116. package/dist/integrations/harnesses/openhands/index.js +1 -0
  117. package/dist/integrations/harnesses/pi/index.js +1 -0
  118. package/dist/integrations/harnesses/shared.js +2 -0
  119. package/dist/integrations/harnesses/types.js +2 -0
  120. package/dist/llm/client.js +41 -11
  121. package/dist/output/cli-hints.js +1 -1
  122. package/dist/output/context.js +10 -19
  123. package/dist/output/format-exempt.js +5 -8
  124. package/dist/output/shapes/helpers.js +1 -22
  125. package/dist/output/shapes/passthrough.js +0 -1
  126. package/dist/output/shapes.js +3 -31
  127. package/dist/output/stdout.js +5 -1
  128. package/dist/output/text/command-format.js +6 -1
  129. package/dist/output/text/workflow-format.js +4 -22
  130. package/dist/scripts/akm-migrate-node.js +13049 -14013
  131. package/dist/scripts/akm-migrate.js +16316 -17276
  132. package/dist/setup/detect.js +10 -4
  133. package/dist/setup/harness-config-import.js +5 -14
  134. package/dist/setup/setup.js +1 -1
  135. package/dist/setup/steps/tasks.js +12 -13
  136. package/dist/storage/repositories/task-history-repository.js +0 -5
  137. package/dist/storage/repositories/workflow-runs-repository.js +5 -15
  138. package/dist/tasks/embedded.js +2 -1
  139. package/dist/tasks/run/task-history.js +0 -2
  140. package/dist/tasks/schedule-gates.js +39 -0
  141. package/dist/tasks/scheduler-binding.js +0 -16
  142. package/dist/tasks/scheduler-sync.js +3 -97
  143. package/dist/tasks/source/bounded-document.js +1 -1
  144. package/dist/tasks/source/task-source-v4.js +2 -12
  145. package/dist/tasks/task-run-reserved-flags.js +2 -31
  146. package/dist/workflows/authoring/authoring.js +6 -6
  147. package/dist/workflows/compile.js +8 -65
  148. package/dist/workflows/exec/child-workflow.js +22 -3
  149. package/dist/workflows/exec/native-executor.js +12 -147
  150. package/dist/workflows/exec/run-workflow.js +31 -103
  151. package/dist/workflows/exec/step-work.js +9 -178
  152. package/dist/workflows/exec/unit-dispatch.js +0 -10
  153. package/dist/workflows/freeze/environment.js +3 -44
  154. package/dist/workflows/freeze/freeze.js +8 -41
  155. package/dist/workflows/freeze/targets/child-workflow.js +27 -63
  156. package/dist/workflows/freeze/targets/command.js +2 -16
  157. package/dist/workflows/freeze/targets/shell.js +0 -2
  158. package/dist/workflows/freeze/task-bindings.js +2 -28
  159. package/dist/workflows/ir/params.js +12 -2
  160. package/dist/workflows/parser.js +82 -232
  161. package/dist/workflows/plan.js +1 -1
  162. package/dist/workflows/renderer.js +10 -19
  163. package/dist/workflows/runtime/run-plan.js +11 -53
  164. package/dist/workflows/runtime/runs.js +4 -27
  165. package/dist/workflows/source-files.js +12 -16
  166. package/dist/workflows/source-semantics.js +1 -93
  167. package/docs/README.md +1 -1
  168. package/docs/agents/README.md +3 -3
  169. package/docs/agents/agent-install.md +1 -1
  170. package/docs/architecture/adapters.md +17 -31
  171. package/docs/architecture/architecture.md +4 -5
  172. package/docs/architecture/improvement.md +52 -21
  173. package/docs/architecture/internals/improve-workflow.md +15 -8
  174. package/docs/architecture/internals/indexing.md +1 -1
  175. package/docs/architecture/internals/search.md +1 -2
  176. package/docs/architecture/internals/storage-locations.md +5 -5
  177. package/docs/architecture/persisted-data-compat.md +13 -4
  178. package/docs/architecture/specs/0.9.0-decisions.md +6 -2
  179. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
  180. package/docs/architecture/specs/workflow-format-unification.md +1 -6
  181. package/docs/architecture/testing/manual-testing-checklist.md +20 -29
  182. package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
  183. package/docs/architecture/testing/testing-workflow.md +1 -1
  184. package/docs/architecture/workflow-engine.md +5 -56
  185. package/docs/guides/author-workflows.md +39 -69
  186. package/docs/guides/capture-knowledge.md +1 -1
  187. package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
  188. package/docs/guides/discover-and-load.md +4 -4
  189. package/docs/guides/getting-started.md +1 -1
  190. package/docs/guides/improve-the-library.md +7 -7
  191. package/docs/guides/recipes/headless-install.md +2 -2
  192. package/docs/guides/run-workflows.md +1 -1
  193. package/docs/guides/use-with-any-agent.md +49 -4
  194. package/docs/integration/bundling-akm.md +7 -6
  195. package/docs/maintainers/curate-workmap.md +1 -2
  196. package/docs/maintainers/release-checklist.md +30 -1
  197. package/docs/posts/akm-command-tour.md +3 -3
  198. package/docs/product-surface.md +1 -1
  199. package/docs/reference/README.md +1 -0
  200. package/docs/reference/api.md +65 -0
  201. package/docs/reference/asset-types.md +3 -5
  202. package/docs/reference/bundle-types.md +2 -4
  203. package/docs/reference/cli.md +129 -171
  204. package/docs/reference/configuration.md +84 -19
  205. package/docs/reference/data-and-telemetry.md +1 -1
  206. package/docs/reference/env-and-secrets.md +2 -2
  207. package/docs/reference/supported-formats.md +3 -4
  208. package/docs/reference/tasks.md +12 -19
  209. package/docs/reference/website-sources.md +1 -1
  210. package/docs/reference/workflow-schema.md +89 -317
  211. package/docs/reference/workflows.md +20 -48
  212. package/package.json +12 -2
  213. package/schemas/akm-config.json +2 -243
  214. package/schemas/akm-task.json +2 -3
  215. package/schemas/akm-workflow.json +47 -84
  216. package/dist/assets/improve-strategies/catchup.json +0 -41
  217. package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
  218. package/dist/assets/improve-strategies/quick.json +0 -17
  219. package/dist/assets/improve-strategies/reflect-distill.json +0 -29
  220. package/dist/assets/improve-strategies/thorough.json +0 -49
  221. package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
  222. package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
  223. package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
  224. package/dist/cli/retired-commands.js +0 -118
  225. package/dist/commands/tasks/validate.js +0 -176
  226. package/dist/core/config/legacy-source-shape-shim.js +0 -117
  227. package/dist/integrations/harnesses/ids.js +0 -28
  228. package/dist/tasks/source/task-source-v3-frozen.js +0 -424
  229. package/dist/tasks/source/task-to-v4.js +0 -863
  230. package/dist/workflows/exec/worktree.js +0 -372
  231. package/dist/workflows/freeze/child-output-references.js +0 -83
  232. package/dist/workflows/freeze/identity.js +0 -22
  233. package/dist/workflows/freeze/targets/script.js +0 -50
  234. package/dist/workflows/freeze/targets/task.js +0 -124
  235. package/dist/workflows/github-yaml.js +0 -506
  236. package/dist/workflows/runtime/run-outputs.js +0 -80
@@ -4,9 +4,7 @@
4
4
  /**
5
5
  * The `akm-workflow` adapter — akm 0.9.0 format-family work item (#46).
6
6
  *
7
- * A native akm workflow bundle. AKM Markdown and the strict local GitHub-shaped
8
- * `.yml` subset are peer source formats. Both compile through the source IR;
9
- * neither source is rewritten or projected onto the other.
7
+ * A native akm workflow bundle: Markdown workflow sources.
10
8
  *
11
9
  * ── validate (spec §6 workflow row) ──
12
10
  *
@@ -21,15 +19,14 @@
21
19
  */
22
20
  import fs from "node:fs";
23
21
  import path from "node:path";
24
- import { looksLikeGithubWorkflowSource } from "../../../workflows/compile.js";
25
22
  import { parseFrontmatter } from "../../asset/frontmatter.js";
26
23
  import { toPosix } from "../../common.js";
27
- import { perTypeValidateChecks, workflowYamlSourceDiagnostics } from "./akm-lint.js";
24
+ import { perTypeValidateChecks } from "./akm-lint.js";
28
25
  import { hashContent, nonEmptyString, readTags, runBaseValidateChecks } from "./shared.js";
29
26
  /** A native workflow bundle is single-component; its one component is `main`. */
30
27
  const COMPONENT_ID = "main";
31
- /** The two authoritative workflow source formats. `.yaml` is deliberately not accepted. */
32
- const WORKFLOW_EXTS = new Set([".md", ".yml"]);
28
+ /** The authoritative workflow source format. */
29
+ const WORKFLOW_EXTS = new Set([".md"]);
33
30
  /** Strip the recognized workflow extension from a component-root-relative path → conceptId. */
34
31
  function conceptIdOf(relPath) {
35
32
  return toPosix(relPath).replace(/\.(?:md|yml)$/i, "");
@@ -94,10 +91,6 @@ async function validate(c, changes, ctx) {
94
91
  if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path.basename(change.path)))
95
92
  continue;
96
93
  const relPath = toPosix(change.path);
97
- if (ext === ".yml") {
98
- diagnostics.push(...workflowYamlSourceDiagnostics(relPath, raw, relPath, c.root).errors);
99
- continue;
100
- }
101
94
  if (!isWorkflowFile(raw))
102
95
  continue;
103
96
  const p = parseFrontmatter(raw);
@@ -140,8 +133,6 @@ function hasTopLevelWorkflowFile(root, entries) {
140
133
  catch {
141
134
  continue;
142
135
  }
143
- if (ext === ".yml" && looksLikeGithubWorkflowSource(raw))
144
- return true;
145
136
  if (ext === ".md" && parseFrontmatter(raw).data.type === "workflow")
146
137
  return true;
147
138
  }
@@ -150,25 +141,15 @@ function hasTopLevelWorkflowFile(root, entries) {
150
141
  export const akmWorkflowAdapter = {
151
142
  id: "akm-workflow",
152
143
  version: "0.9.2",
153
- extensions: [".md", ".yml"],
144
+ extensions: [".md"],
154
145
  recognize,
155
146
  validate,
156
147
  readCandidates(c, conceptId) {
157
148
  const posix = toPosix(conceptId);
158
- const canonical = posix.replace(/\.(?:md|yml)$/i, "");
159
- return /\.(?:md|yml)$/i.test(posix)
149
+ const canonical = posix.replace(/\.md$/i, "");
150
+ return /\.md$/i.test(posix)
160
151
  ? [{ path: path.join(c.root, posix), conceptId: canonical }]
161
- : [
162
- { path: path.join(c.root, `${posix}.md`), conceptId: canonical },
163
- { path: path.join(c.root, `${posix}.yml`), conceptId: canonical },
164
- ];
165
- },
166
- /** Markdown remains the default; an explicit `.md`/`.yml` suffix is preserved. */
167
- placeNew(c, conceptId) {
168
- const posix = toPosix(conceptId);
169
- if (/\.(?:md|yml)$/i.test(posix))
170
- return path.join(c.root, posix);
171
- return path.join(c.root, `${posix}.md`);
152
+ : [{ path: path.join(c.root, `${posix}.md`), conceptId: canonical }];
172
153
  },
173
154
  /** Workflows live anywhere under the component root. */
174
155
  directoryList() {
@@ -176,7 +157,7 @@ export const akmWorkflowAdapter = {
176
157
  },
177
158
  /**
178
159
  * Install-time probe (§1.2): a root holding an explicitly typed Markdown
179
- * workflow or a complete GitHub-shaped YAML workflow at top level.
160
+ * workflow at top level.
180
161
  */
181
162
  looksLikeRoot(root) {
182
163
  let entries;
@@ -29,7 +29,7 @@
29
29
  */
30
30
  import fs from "node:fs";
31
31
  import path from "node:path";
32
- import { assetPathCandidatesForName, assetPathForName, typeForStashDir } from "../../asset/asset-placement.js";
32
+ import { assetPathCandidatesForName, typeForStashDir } from "../../asset/asset-placement.js";
33
33
  import { scanEnvKeyNames, toPosix } from "../../common.js";
34
34
  import { dangerousEnvKeyDiagnostics } from "./akm-lint.js";
35
35
  import { hashContent } from "./shared.js";
@@ -171,25 +171,6 @@ export const dotenvAdapter = {
171
171
  : [primary, `${primary}.sensitive`, `${primary}.lock`]);
172
172
  return expanded.map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
173
173
  },
174
- /**
175
- * env places to `env/<name>.env`, secret to `secrets/<name>` (identity join,
176
- * no extension logic) — reusing the shared `assetPathForName` so the env
177
- * default-alias / already-suffixed / nested-secret edge cases match the akm
178
- * placement convention exactly.
179
- */
180
- placeNew(c, conceptId) {
181
- const posix = toPosix(conceptId);
182
- const slash = posix.indexOf("/");
183
- if (slash > 0) {
184
- const head = posix.slice(0, slash);
185
- const rest = posix.slice(slash + 1);
186
- const type = typeForStashDir(head);
187
- if ((type === "env" || type === "secret") && rest.length > 0) {
188
- return assetPathForName(type, path.join(c.root, head), rest);
189
- }
190
- }
191
- return path.join(c.root, posix);
192
- },
193
174
  /** The dotenv bundle owns its `env/` + `secrets/` dirs. */
194
175
  directoryList() {
195
176
  return [ENV_DIR, SECRETS_DIR];
@@ -107,16 +107,6 @@ export const genericFilesAdapter = {
107
107
  ? documentCandidates
108
108
  : [{ path: path.join(c.root, posix), conceptId: posix }, ...documentCandidates];
109
109
  },
110
- /**
111
- * IDENTITY placement (open-question-5): a conceptId that carries an extension
112
- * (`script`/`file`) places to itself; an extension-less conceptId (a
113
- * `document`) appends `.md`.
114
- */
115
- placeNew(c, conceptId) {
116
- const posix = toPosix(conceptId);
117
- const hasExt = path.extname(posix) !== "";
118
- return path.join(c.root, hasExt ? posix : `${posix}.md`);
119
- },
120
110
  /** generic-files is EXPLICIT-CONFIG ONLY — never auto-selected (§1.2), so this never fires. */
121
111
  looksLikeRoot() {
122
112
  return false;
@@ -395,10 +395,6 @@ export const llmWikiAdapter = {
395
395
  const canonical = toPosix(conceptId).replace(/\.md$/i, "");
396
396
  return [{ path: path.join(c.root, `${canonical}.md`), conceptId: canonical }];
397
397
  },
398
- /** `<c.root>/<conceptId>.md` — the conceptId already carries its `pages/`/`raw/` prefix (placement golden). */
399
- placeNew(c, conceptId) {
400
- return path.join(c.root, `${conceptId}.md`);
401
- },
402
398
  /** The wiki owns its whole root (schema/index/log at root plus pages/ + raw/); one component. */
403
399
  directoryList(_c) {
404
400
  return ["."];
@@ -126,29 +126,6 @@ export function recognizeToolDir(layout, c, file) {
126
126
  doc.tags = tags;
127
127
  return doc;
128
128
  }
129
- /**
130
- * placeNew() for a tool-dir adapter (spec §7: "AKM workspace layout IS the tool
131
- * dir minus the prefix"). Writes NORMALIZE to the canonical plural subdir
132
- * (open-question-6): a `command/foo` concept still places at `commands/foo.md`.
133
- * The instruction file is fixed at the component root.
134
- */
135
- export function placeNewToolDir(layout, c, conceptId) {
136
- const posix = toPosix(conceptId);
137
- if (posix === layout.instructionConceptId)
138
- return path.join(c.root, layout.instructionFile);
139
- const segs = posix.split("/").filter((s) => s.length > 0);
140
- const head = segs[0];
141
- const rest = segs.slice(1).join("/");
142
- if (rest.length > 0) {
143
- if (layout.skillDirs.has(head))
144
- return path.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST);
145
- if (layout.commandDirs.has(head))
146
- return path.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
147
- if (layout.agentDirs.has(head))
148
- return path.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
149
- }
150
- return path.join(c.root, `${posix}.md`);
151
- }
152
129
  /** List native read spellings. */
153
130
  export function readCandidatesToolDir(layout, c, conceptId) {
154
131
  const posix = toPosix(conceptId);
@@ -263,7 +240,6 @@ export function makeToolDirAdapter(layout, looksLikeRoot) {
263
240
  renderExecutionSource: (c, file) => renderToolDirExecutionSource(layout, c, file),
264
241
  validate: (c, changes, ctx) => validateToolDir(layout, c, changes, ctx),
265
242
  readCandidates: (c, conceptId) => readCandidatesToolDir(layout, c, conceptId),
266
- placeNew: (c, conceptId) => placeNewToolDir(layout, c, conceptId),
267
243
  directoryList: () => [CANONICAL_COMMAND_DIR, CANONICAL_AGENT_DIR, CANONICAL_SKILL_DIR],
268
244
  looksLikeRoot,
269
245
  };
@@ -15,8 +15,8 @@
15
15
  * `stash/knowledge/` prefix. `manifest.json` is snapshot PROVENANCE
16
16
  * (`{url, fetchedAt}`), read by the probe but never indexed as a concept.
17
17
  *
18
- * Read-only ⇒ NO `placeNew` (Mode B export routes content through the
19
- * DESTINATION adapter, which owns placement). `validate` runs base checks only
18
+ * Read-only (Mode B export routes content through the DESTINATION adapter,
19
+ * which owns placement). `validate` runs base checks only
20
20
  * (a mirror the adapter does not author has no native validators); `updated`
21
21
  * never appears on a snapshot page, so `missing-updated` is filtered out.
22
22
  *
@@ -129,8 +129,8 @@ export const websiteSnapshotAdapter = {
129
129
  const canonical = toPosix(conceptId).replace(/\.md$/i, "");
130
130
  return [{ path: path.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
131
131
  },
132
- // No placeNew: the snapshot is READ-ONLY (Mode A). Export (Mode B) routes
133
- // content through the DESTINATION adapter, which owns placement.
132
+ // The snapshot is READ-ONLY (Mode A). Export (Mode B) routes content through
133
+ // the DESTINATION adapter, which owns placement.
134
134
  /**
135
135
  * Install-time probe (§1.2): a root carrying the snapshot provenance
136
136
  * `manifest.json` (`{url, fetchedAt}`). No other bundle root carries this
@@ -7,10 +7,9 @@ import { directoryMatcher, extensionMatcher, parentDirHintMatcher, smartMdMatche
7
7
  * registration index `runMatchers` uses for tie-breaking. (The `wiki` matcher
8
8
  * was removed in chunk 4 — the wiki asset-type is retired; LLM Wiki content is
9
9
  * served by the first-class `llm-wiki` adapter, not the akm adapter. The old
10
- * YAML workflow-program matcher is also gone: peer Markdown and GitHub-shaped
11
- * `.yml` workflow sources are both path-owned by residence under `workflows/`
12
- * (with Markdown frontmatter as an additional signal), while source IR owns
13
- * their distinct parse/compile semantics.)
10
+ * YAML workflow-program matcher is also gone: Markdown workflow sources are
11
+ * path-owned by residence under `workflows/`, with Markdown frontmatter as an
12
+ * additional signal.)
14
13
  */
15
14
  const AKM_MATCHERS = [
16
15
  extensionMatcher,
@@ -4,7 +4,6 @@
4
4
  import crypto from "node:crypto";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
- import { migrateLegacySourceShape } from "./config/legacy-source-shape-shim.js";
8
7
  import { ConfigError } from "./errors.js";
9
8
  import { getConfigPath, getDefaultStashDir, getRegistryCacheDir, getRegistryIndexCacheDir } from "./paths.js";
10
9
  // ── Constants ───────────────────────────────────────────────────────────────
@@ -306,7 +305,7 @@ function readStashDirFromConfig() {
306
305
  const parsed = JSON.parse(stripJsonComments(text));
307
306
  if (typeof parsed !== "object" || parsed === null)
308
307
  return undefined;
309
- const raw = migrateLegacySourceShape(parsed, configPath);
308
+ const raw = parsed;
310
309
  // 0.9.0 config-shape cutover (spec §10.1): the primary stash is the
311
310
  // `defaultBundle`'s filesystem `path`. Read it directly (no config module
312
311
  // import) so the primary-stash location survives the stashDir → bundles
@@ -920,6 +919,23 @@ export function wellFormedUnicode(value) {
920
919
  export function isRecord(value) {
921
920
  return typeof value === "object" && value !== null && !Array.isArray(value);
922
921
  }
922
+ /** The value when it is a plain object, else undefined (for `?.` chains over unknown JSON). */
923
+ export function asRecord(value) {
924
+ return isRecord(value) ? value : undefined;
925
+ }
926
+ /**
927
+ * Parse JSONC: comments stripped by {@link stripJsonComments}, and trailing
928
+ * commas (`[a, b,]`, `{"k": 1,}`) tolerated, as OpenCode's own `.jsonc` reader does.
929
+ */
930
+ export function parseJsonc(text) {
931
+ const stripped = stripJsonComments(text);
932
+ try {
933
+ return JSON.parse(stripped);
934
+ }
935
+ catch {
936
+ return JSON.parse(stripped.replace(/,(\s*[}\]])/g, "$1"));
937
+ }
938
+ }
923
939
  /** `JSON.parse` that returns `undefined` instead of throwing. */
924
940
  export function tryParseJson(raw) {
925
941
  try {
@@ -39,8 +39,8 @@
39
39
  * enforced at save time via `superRefine` on the top-level schema.
40
40
  */
41
41
  import { z } from "zod";
42
- import { HARNESS_MODEL_WORK_IDS } from "../../integrations/harnesses/ids.js";
43
- import { BUILTIN_IMPROVE_STRATEGY_NAMES, IMPROVE_ENGINE_PROCESSES } from "./engine-semantics.js";
42
+ import { HARNESS_MODEL_WORK_IDS } from "../../integrations/harnesses/index.js";
43
+ import { BUILTIN_IMPROVE_STRATEGY_NAMES, IMPROVE_ENGINE_PROCESSES, REMOVED_IMPROVE_STRATEGY_NAMES, } from "./engine-semantics.js";
44
44
  import { EmbeddingConnectionConfigSchema } from "./schema/embedding.js";
45
45
  import { EnginesSchema } from "./schema/engines.js";
46
46
  import { ExecutionPolicyConfigSchema } from "./schema/execution.js";
@@ -113,8 +113,9 @@ export const AkmConfigShape = {
113
113
  index: IndexConfigSchema.optional(),
114
114
  registries: z.array(RegistryConfigEntrySchema).optional(),
115
115
  // `bundles` + `defaultBundle` are the only source configuration shape. The
116
- // retired `stashDir`/`sources[]`/`installed[]` keys are rejected at load;
117
- // there is no runtime config translator. `defaultBundle` names the primary
116
+ // retired `stashDir`/`sources[]`/`installed[]` keys are rejected at load,
117
+ // naming the 0.9.x `akm migrate apply` that converts them; there is no
118
+ // runtime config translator. `defaultBundle` names the primary
118
119
  // bundle used for short-ref resolution.
119
120
  bundles: BundlesConfigSchema.optional(),
120
121
  defaultBundle: nonEmptyString.optional(),
@@ -138,8 +139,10 @@ export const AkmConfigBaseSchema = z.object(AkmConfigShape).passthrough();
138
139
  * Per-key overrides for unsupported pre-cutover source shapes.
139
140
  */
140
141
  const RETIRED_SOURCE_SHAPE_KEY_MESSAGES = {
141
- stashDir: "stashDir is not supported; configure `bundles`, or use `akm config path --all` / `akm info` to inspect current paths.",
142
+ stashDir: "stashDir is not supported; configure `bundles`, or use `akm info` to inspect current paths.",
142
143
  };
144
+ /** The one message for a config older than 0.9.15: only akm 0.9.x converts it. */
145
+ const PRE_FLOOR_CONFIG_REMEDY = "This config predates akm 0.9.15 and 0.10 does not convert it: run `akm migrate apply` with akm 0.9.x, then upgrade.";
143
146
  export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
144
147
  const raw = config;
145
148
  // Only the current source shape enters the runtime. There is no config
@@ -149,7 +152,7 @@ export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) =>
149
152
  ctx.addIssue({
150
153
  code: z.ZodIssueCode.custom,
151
154
  path: [key],
152
- message: RETIRED_SOURCE_SHAPE_KEY_MESSAGES[key] ?? `${key} is not supported; configure the current bundles shape`,
155
+ message: `${RETIRED_SOURCE_SHAPE_KEY_MESSAGES[key] ?? `${key} is not supported; configure the current bundles shape`} ${PRE_FLOOR_CONFIG_REMEDY}`,
153
156
  });
154
157
  }
155
158
  }
@@ -194,15 +197,6 @@ export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) =>
194
197
  });
195
198
  }
196
199
  }
197
- for (const key of ["llm", "agent", "improve"]) {
198
- if (config.defaults && key in config.defaults) {
199
- ctx.addIssue({
200
- code: z.ZodIssueCode.custom,
201
- path: ["defaults", key],
202
- message: `defaults.${key} is retired in 0.9`,
203
- });
204
- }
205
- }
206
200
  for (const [name, engine] of Object.entries(config.engines ?? {})) {
207
201
  if (engine.kind === "agent" && engine.llmEngine) {
208
202
  const fallback = config.engines?.[engine.llmEngine];
@@ -267,6 +261,9 @@ export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) =>
267
261
  // (src/commands/improve/improve-strategies.ts) refuses it lazily, at
268
262
  // improve-invocation time, with the same message either way.
269
263
  defaultStrategy !== "graph-refresh" &&
264
+ // The strategies removed in 0.10 (#1130) are exempt for the same reason:
265
+ // `resolveImproveStrategy` refuses them lazily, naming `default`.
266
+ !REMOVED_IMPROVE_STRATEGY_NAMES.includes(defaultStrategy) &&
270
267
  !BUILTIN_IMPROVE_STRATEGY_NAMES.includes(defaultStrategy) &&
271
268
  !config.improve?.strategies?.[defaultStrategy]) {
272
269
  ctx.addIssue({
@@ -1,21 +1,12 @@
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
- // VALID_HARNESS_IDS / HARNESS_AGENT_DISPATCH_IDS derive from the dependency-free
5
- // harnesses/ids.ts leaf (WI-9.8 KILL 3), NOT the full HARNESS_REGISTRY barrel
6
- // (`../../integrations/harnesses`) — that barrel transitively pulls in every
7
- // harness's agent-builder and the agent runtime, which is what fused config
8
- // into the same import-cycle SCC as `integrations/agent/*`. `harnesses/index.ts`
9
- // asserts at construction time that its registry matches this leaf, so the two
10
- // cannot silently drift (see `tests/harnesses-registry.test.ts` for the
11
- // value-level pin). config ← harnesses/ids is the only import direction (the
12
- // leaf imports nothing), so there is no cycle.
13
- import { HARNESS_AGENT_DISPATCH_IDS, VALID_HARNESS_IDS } from "../../integrations/harnesses/ids.js";
4
+ // Harness ids derive from the harness registry; nothing the registry imports
5
+ // reaches `core/config` at runtime, so there is no cycle.
6
+ import { HARNESS_AGENT_DISPATCH_IDS, VALID_HARNESS_IDS } from "../../integrations/harnesses/index.js";
14
7
  /**
15
- * Canonical list of valid agent harness / platform ids. Derived from the
16
- * dependency-free harness-id leaf (#562/WI-9.8) so the Zod `AgentPlatformSchema`
17
- * enum, the agent-engine platform union, and setup's `DetectedHarness` union
18
- * all derive from one place and cannot drift. Add a harness in
19
- * `src/integrations/harnesses/index.ts` (and its `ids.ts` mirror entry).
8
+ * Canonical list of valid agent harness / platform ids, derived from the harness
9
+ * registry so the Zod `AgentPlatformSchema` enum, the agent-engine platform
10
+ * union, and setup's `DetectedHarness` union cannot drift.
20
11
  */
21
12
  export { HARNESS_AGENT_DISPATCH_IDS, VALID_HARNESS_IDS };
@@ -34,11 +34,11 @@ import { isApiKeyReference } from "./schema/primitives.js";
34
34
  */
35
35
  function parsePath(dotted) {
36
36
  if (!dotted) {
37
- throw new UsageError("Config key is required.", "INVALID_FLAG_VALUE", unknownKeyHint(""));
37
+ throw new UsageError("Config key is required.", "INVALID_FLAG_VALUE", unknownKeyHint());
38
38
  }
39
39
  const segments = dotted.split(".");
40
40
  if (segments.some((s) => !s)) {
41
- throw new UsageError(`Invalid config key "${dotted}": empty segment between dots.`, "INVALID_FLAG_VALUE", unknownKeyHint(dotted));
41
+ throw new UsageError(`Invalid config key "${dotted}": empty segment between dots.`, "INVALID_FLAG_VALUE", unknownKeyHint());
42
42
  }
43
43
  return segments;
44
44
  }
@@ -150,7 +150,7 @@ export function configGet(config, dotted) {
150
150
  const path = parsePath(dotted);
151
151
  const schema = resolveSchemaAt(path, config);
152
152
  if (!schema) {
153
- throw new UsageError(`Unknown config key: ${dotted}`, "INVALID_FLAG_VALUE", unknownKeyHint(dotted));
153
+ throw new UsageError(`Unknown config key: ${dotted}`, "INVALID_FLAG_VALUE", unknownKeyHint());
154
154
  }
155
155
  let cursor = config;
156
156
  for (const segment of path) {
@@ -266,7 +266,7 @@ export function configUnset(config, dotted) {
266
266
  // Validate the path resolves to a real schema field (so typos don't no-op).
267
267
  const schema = resolveSchemaAt(path, config);
268
268
  if (!schema) {
269
- throw new UsageError(`Unknown config key: ${dotted}`, "INVALID_FLAG_VALUE", unknownKeyHint(dotted));
269
+ throw new UsageError(`Unknown config key: ${dotted}`, "INVALID_FLAG_VALUE", unknownKeyHint());
270
270
  }
271
271
  return unsetPath(config, path);
272
272
  }
@@ -467,24 +467,7 @@ function unsetPath(config, path) {
467
467
  return next;
468
468
  }
469
469
  // ── Hint generation (#460) ──────────────────────────────────────────────────
470
- /**
471
- * Per-key "use X instead" guidance for config keys retired before the 0.9
472
- * cutover, keyed on the first dotted-path segment. Mitigation item 3: the
473
- * generic "valid top-level keys" hint doesn't tell a pre-0.9 user what
474
- * replaced the key they typed — this does.
475
- */
476
- const RETIRED_KEY_HINTS = {
477
- stashDir: "stashDir was removed in 0.9; get the stash path from `akm config path --all` or `akm info`.",
478
- sources: "sources is not supported; configure `bundles` instead.",
479
- installed: "installed is not supported; configure `bundles` instead.",
480
- wikiName: "the wiki subsystem was removed in 0.9; wikis are ordinary knowledge assets now — see `akm import`.",
481
- wiki: "the wiki subsystem was removed in 0.9; wikis are ordinary knowledge assets now — see `akm import`.",
482
- llm: "llm was replaced by named engines configuration in 0.9; configure `engines` instead.",
483
- };
484
- export function unknownKeyHint(attempted) {
470
+ export function unknownKeyHint() {
485
471
  const keys = listTopLevelConfigKeys();
486
- const generic = `Valid top-level keys: ${keys.join(", ")}. Use dotted paths for nested values (e.g. embedding.endpoint, engines.<name>.model).`;
487
- const firstSegment = attempted.split(".")[0] ?? "";
488
- const retiredHint = RETIRED_KEY_HINTS[firstSegment];
489
- return retiredHint ? `${retiredHint} ${generic}` : generic;
472
+ return `Valid top-level keys: ${keys.join(", ")}. Use dotted paths for nested values (e.g. embedding.endpoint, engines.<name>.model).`;
490
473
  }
@@ -5,18 +5,16 @@ import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  import { isDeepStrictEqual } from "node:util";
8
- import { isBundleSlug, parseBundleRef } from "../asset/asset-ref.js";
8
+ import { isBundleSlug } from "../asset/asset-ref.js";
9
9
  import { deriveBundleId } from "../bundle-id.js";
10
10
  import { isRecord, resolveStashDir } from "../common.js";
11
11
  import { ConfigError } from "../errors.js";
12
- import { liftLegacyEngineExtraParams } from "../extra-params.js";
13
12
  import { formatRegistryLabel, hasRegistryUrlCredentials } from "../registry-url.js";
14
13
  import { acquireConfigLock, backupExistingConfig, parseConfigText, readConfigText, withConfigLock, writeConfigAtomic, } from "./config-io.js";
15
14
  import { AkmConfigSchema, CURRENT_CONFIG_VERSION } from "./config-schema.js";
16
15
  import { bundleComponentConfig, bundleContentRoot, bundleContentRoots, bundleSourceId, bundlesToSourceEntries, filesystemBundleSourceId, isBundleEnabled, } from "./config-sources.js";
17
16
  import { resolveSchemaAt } from "./config-walker.js";
18
17
  import { deepMergeConfig, isPlainObject } from "./deep-merge.js";
19
- import { migrateLegacySourceShape } from "./legacy-source-shape-shim.js";
20
18
  import { isApiKeyReference, SECRET_STORE_REFERENCE_PATTERN } from "./schema/primitives.js";
21
19
  export { stripJsonComments } from "./config-io.js";
22
20
  import { getConfigPath } from "../paths.js";
@@ -95,18 +93,16 @@ export function loadUserConfig() {
95
93
  * Run the per-file config pipeline every raw config object goes through
96
94
  * before it is either validated (the local/top-level file) or merged in as
97
95
  * an `extends` base: JSONC parse already done by the caller, then the
98
- * `configVersion` read ({@link readConfigVersion}), then the legacy
99
- * `stashDir`/`sources[]`/`installed[]` shim, then the legacy `extraParams`
100
- * lift (#852). Unknown keys are not an error: the schema drops them in
101
- * memory. Shared by {@link parseAndValidateConfigText} (the local file) and
102
- * {@link resolveExtendsChain} (each base in the chain) so a fleet-shared base
103
- * config can carry its own `configVersion` / legacy shape independently of
96
+ * `configVersion` read ({@link readConfigVersion}). Unknown keys are not an
97
+ * error: the schema drops them in memory. A shape older than 0.9.15 is not
98
+ * converted here; it fails validation with a message naming `akm migrate
99
+ * apply` under akm 0.9.x. Shared by {@link parseAndValidateConfigText} (the
100
+ * local file) and {@link resolveExtendsChain} (each base in the chain) so a
101
+ * fleet-shared base config can carry its own `configVersion` independently of
104
102
  * the file that extends it.
105
103
  */
106
104
  function runConfigFilePipeline(text, sourcePath) {
107
- const versioned = readConfigVersion(parseConfigText(text, sourcePath), sourcePath);
108
- const parsedRaw = migrateLegacySourceShape(versioned, sourcePath);
109
- return liftExtraParamsOrThrow(parsedRaw, sourcePath);
105
+ return readConfigVersion(parseConfigText(text, sourcePath), sourcePath);
110
106
  }
111
107
  /**
112
108
  * `configVersion` is read, never gated on. `"0.9.0"` is the only value akm
@@ -124,30 +120,6 @@ function readConfigVersion(raw, sourcePath) {
124
120
  }
125
121
  return { ...raw, configVersion: CURRENT_CONFIG_VERSION };
126
122
  }
127
- /**
128
- * #852 (following #815): a config still using legacy `extraParams` keys —
129
- * e.g. `reasoning_effort`, a documented 0.9.1 workaround — needs to be
130
- * rewritten onto the first-class engine field they now shadow. This used
131
- * to happen silently, in memory, on every load; that ran forever and never
132
- * converged. The lift itself is now `akm migrate apply`'s job (see
133
- * scripts/akm-migrate/migrate/config-extra-params.ts) and persists to disk, so a
134
- * config that has not been migrated yet fails closed here instead of
135
- * silently drifting from what's on disk.
136
- */
137
- function liftExtraParamsOrThrow(parsedRaw, sourcePath) {
138
- const where = sourcePath ? ` at ${sourcePath}` : "";
139
- const { config: liftedConfig, lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
140
- if (conflicts.length > 0) {
141
- const lines = conflicts
142
- .map((c) => ` - engines.${c.engine}.extraParams.${c.key} (${JSON.stringify(c.extraParamsValue)}) conflicts with engines.${c.engine}.${c.field} (${JSON.stringify(c.fieldValue)})`)
143
- .join("\n");
144
- throw new ConfigError(`Invalid config${where}: extraParams and the first-class field disagree:\n${lines}\n\nEach extraParams key above has a first-class equivalent and akm will not guess which value you meant — remove the extraParams entry once the field carries the value you want.`, "INVALID_CONFIG_FILE");
145
- }
146
- if (lifted.length > 0) {
147
- warnOnce(`config:extra-params-lift${sourcePath ? `:${sourcePath}` : ""}`, `Config${where} uses deprecated extraParams keys with first-class equivalents — auto-lifted in memory:\n - ${lifted.join("\n - ")}\n\nRun \`akm migrate apply\` to rewrite the config file and silence this warning.`);
148
- }
149
- return liftedConfig;
150
- }
151
123
  /**
152
124
  * Resolve a local file's `extends` chain and validate the merged result
153
125
  * (deep-merged under `DEFAULT_CONFIG`) via Zod ({@link AkmConfigSchema}).
@@ -184,10 +156,11 @@ function buildEffectiveConfig(liftedLocalRaw, sourcePath) {
184
156
  * guarantees apply as any other retired config key (AGENTS.md "Reading
185
157
  * persisted data"): a config setting one keeps loading, is named once by
186
158
  * the unknown-key warning, and is dropped only by `akm migrate apply`.
187
- * Both were retired in 0.9.17-alpha.9: `index.graph` (the LLM entity-graph
188
- * extraction pass) and `index.metadataEnhance` (LLM metadata enrichment).
159
+ * `index.graph` (the LLM entity-graph extraction pass) and
160
+ * `index.metadataEnhance` (LLM metadata enrichment) were retired in
161
+ * 0.9.17-alpha.9; `index.stalenessDetection` before them.
189
162
  */
190
- const RETIRED_CATCHALL_KEY_PATHS = new Set(["index.graph", "index.metadataEnhance"]);
163
+ const RETIRED_CATCHALL_KEY_PATHS = new Set(["index.graph", "index.metadataEnhance", "index.stalenessDetection"]);
191
164
  /**
192
165
  * Every dotted key in `raw` the schema does not know, at any depth (arrays
193
166
  * are not descended). Unknown keys are never an error: they are a typo, or a
@@ -656,9 +629,9 @@ function configWriteBody(localRaw, current, next, persistTopLevelKeys = []) {
656
629
  }
657
630
  /**
658
631
  * The migrator's one config step. The reader already tolerates every shape
659
- * akm has written (`configVersion` read as current, legacy source layout,
660
- * `extraParams` lift, unknown keys dropped); this writes that current shape back to
661
- * `config.json` — the same body `mutateConfig` writes — so the tolerance
632
+ * 0.9.15 and later wrote (`configVersion` read as current, 0.9.16
633
+ * `{kind, ref, sourceId}` scheduler entries, unknown keys dropped); this
634
+ * writes that current shape back to `config.json` — the same body `mutateConfig` writes — so the tolerance
662
635
  * becomes durable. Reports without writing unless `apply` is set.
663
636
  */
664
637
  export function normalizeConfigFile(configPath, options) {
@@ -670,7 +643,7 @@ export function normalizeConfigFile(configPath, options) {
670
643
  const localRaw = runConfigFilePipeline(text, configPath);
671
644
  const current = buildEffectiveConfig(localRaw, configPath);
672
645
  const next = validateCompleteConfig({ ...current, configVersion: CURRENT_CONFIG_VERSION });
673
- const body = withSchedulerOnDisk(configWriteBody(localRaw, current, next), next);
646
+ const body = configWriteBody(localRaw, current, next);
674
647
  for (const keyPath of unknownConfigKeyPaths(body))
675
648
  deleteConfigPath(body, keyPath);
676
649
  // `improve.strategies["graph-refresh"]` is schema-valid (any name is a
@@ -747,7 +720,6 @@ export async function mutateConfigWithPrecommit(mutate, precommit, options) {
747
720
  release();
748
721
  }
749
722
  }
750
- const UNBOUND_SCHEDULER_SOURCE_ID = `sha256:${"0".repeat(64)}`;
751
723
  /**
752
724
  * The source identity 0.9.16 bound a scheduler grant to: the configured
753
725
  * bundle's source id, or the implicit `AKM_BUNDLE_DIR` stash's. `undefined`
@@ -767,41 +739,6 @@ export function schedulerSourceIdFor(config, bundleId) {
767
739
  return undefined;
768
740
  }
769
741
  }
770
- /**
771
- * `scheduler.enabled` is a list of refs in memory but is written in the
772
- * `{kind, ref, sourceId}` shape 0.9.16 reads, so that release still runs
773
- * against a config this one wrote (the upgrade rehearsal's read-back). This
774
- * release reads either shape; the object form can go once no supported
775
- * release is strict about it.
776
- */
777
- function schedulerEnabledOnDisk(config) {
778
- const enabled = config.scheduler?.enabled;
779
- if (enabled === undefined)
780
- return undefined;
781
- return enabled.map((ref) => {
782
- let bundle;
783
- let conceptId = "";
784
- try {
785
- const parsed = parseBundleRef(ref);
786
- bundle = parsed.bundle;
787
- conceptId = parsed.conceptId;
788
- }
789
- catch {
790
- return ref;
791
- }
792
- return {
793
- kind: conceptId.startsWith("workflows/") ? "workflow" : "task",
794
- ref,
795
- sourceId: (bundle !== undefined ? schedulerSourceIdFor(config, bundle) : undefined) ?? UNBOUND_SCHEDULER_SOURCE_ID,
796
- };
797
- });
798
- }
799
- function withSchedulerOnDisk(body, config) {
800
- const onDisk = schedulerEnabledOnDisk(config);
801
- if (onDisk === undefined || !isPlainConfigObject(body.scheduler))
802
- return body;
803
- return { ...body, scheduler: { ...body.scheduler, enabled: onDisk } };
804
- }
805
742
  /**
806
743
  * Strip literal apiKey fields before writing config to disk.
807
744
  * API keys are expected to come from environment variables
@@ -866,7 +803,7 @@ export function sanitizeConfigForWrite(config) {
866
803
  warn(`Config sanitizer dropped registry entr${droppedRegistries.length === 1 ? "y" : "ies"} with URL credentials before writing to disk:\n - ${droppedRegistries.join("\n - ")}\n\nRegistry URLs must be credential-free; configure a credential-free HTTPS endpoint.`);
867
804
  }
868
805
  }
869
- return withSchedulerOnDisk(sanitized, config);
806
+ return sanitized;
870
807
  }
871
808
  export function updateConfig(partial) {
872
809
  return mutateConfig((current) => deepMergeConfig(current, partial)).config;
@@ -2,11 +2,15 @@
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
  export const ENGINE_NAME_PATTERN_SOURCE = "^(?!akm-)[a-z][a-z0-9]*(?:-[a-z0-9]+)*$";
5
- export const BUILTIN_IMPROVE_STRATEGY_NAMES = [
6
- "default",
5
+ export const BUILTIN_IMPROVE_STRATEGY_NAMES = ["default", "consolidate"];
6
+ /**
7
+ * Built-in strategies removed in 0.10 (#1130, #1129). A user-defined strategy of the
8
+ * same name still resolves (it inherits `default`); naming one with no such
9
+ * block fails at resolution, not at config load.
10
+ */
11
+ export const REMOVED_IMPROVE_STRATEGY_NAMES = [
7
12
  "quick",
8
13
  "thorough",
9
- "consolidate",
10
14
  "catchup",
11
15
  "reflect-distill",
12
16
  "proactive-maintenance",
@@ -7,13 +7,13 @@
7
7
  * no behavior change.
8
8
  */
9
9
  import { z } from "zod";
10
- // Harness ids come straight from the dependency-free `harnesses/ids` leaf (the
11
- // same source `config-types.ts` re-exports them from). Importing them here
12
- // rather than via `../config-types` keeps `schema/*` free of any edge to
13
- // `config-types`, which type-derives from this barrel via
14
- // `typeof import("./config-schema")` — routing through config-types would mint
15
- // a config-schema ↔ config-types type cycle that collapses inference.
16
- import { HARNESS_AGENT_DISPATCH_IDS, HARNESS_NATIVE_AGENT_IDS, VALID_HARNESS_IDS, } from "../../../integrations/harnesses/ids.js";
10
+ // Harness ids come straight from the harness registry (the same source
11
+ // `config-types.ts` re-exports them from). Importing them here rather than via
12
+ // `../config-types` keeps `schema/*` free of any edge to `config-types`, which
13
+ // type-derives from this barrel via `typeof import("./config-schema")` —
14
+ // routing through config-types would mint a config-schema ↔ config-types type
15
+ // cycle that collapses inference.
16
+ import { HARNESS_AGENT_DISPATCH_IDS, HARNESS_NATIVE_AGENT_IDS, VALID_HARNESS_IDS, } from "../../../integrations/harnesses/index.js";
17
17
  import { WORKFLOW_MAX_TIMEOUT_MS } from "../../../workflows/resource-limits.js";
18
18
  import { chatCompletionsEndpoint, ExtraParamsSchema, engineName, nonEmptyString, positiveInt, symbolicOrWarnApiKey, } from "./primitives.js";
19
19
  /**