akm-cli 0.9.31 → 0.10.261002-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.
- package/CHANGELOG.md +420 -0
- package/STABILITY.md +99 -57
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +15 -29
- package/dist/assets/hints/cli-hints-short.md +2 -2
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/feedback-cli.js +75 -49
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/chunking.js +3 -10
- package/dist/commands/improve/consolidate/continuity-check.js +4 -4
- package/dist/commands/improve/consolidate/pair-pass.js +29 -10
- package/dist/commands/improve/consolidate.js +10 -65
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +148 -21
- package/dist/commands/improve/eligibility.js +14 -1
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/extract-prompt.js +17 -7
- package/dist/commands/improve/extract.js +5 -7
- package/dist/commands/improve/improve-cli.js +92 -106
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/improve.js +134 -52
- package/dist/commands/improve/loop-stages.js +18 -5
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +29 -34
- package/dist/commands/improve/retrieval-queries.js +37 -0
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/session-asset.js +4 -1
- package/dist/commands/improve/stage.js +23 -12
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +43 -6
- package/dist/commands/proposal/proposal-cli.js +11 -31
- package/dist/commands/proposal/repository.js +20 -14
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +6 -14
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +10 -63
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +2 -6
- package/dist/core/improve-result.js +13 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/paths.js +4 -0
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/run-lock.js +1 -1
- package/dist/core/subprocess.js +49 -0
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/indexer.js +15 -6
- package/dist/indexer/passes/memory-inference.js +15 -6
- package/dist/indexer/search/db-search.js +49 -36
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/indexer/search/ranking.js +29 -1
- package/dist/indexer/usage/usage-events.js +21 -16
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +41 -11
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15745 -16711
- package/dist/scripts/akm-migrate.js +16318 -17280
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/sources/providers/git-stash.js +113 -16
- package/dist/storage/repositories/index-utility-repository.js +2 -32
- package/dist/storage/repositories/index-vec-repository.js +4 -0
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/run-command-task.js +9 -1
- package/dist/tasks/run/run-workflow-task.js +4 -3
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/run/task-log.js +38 -1
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +1 -1
- package/docs/agents/README.md +3 -3
- package/docs/agents/agent-install.md +1 -1
- package/docs/architecture/0.10-process-rules.md +827 -0
- package/docs/architecture/adapters.md +17 -31
- package/docs/architecture/architecture.md +4 -5
- package/docs/architecture/improvement.md +115 -76
- package/docs/architecture/internals/improve-workflow.md +22 -16
- package/docs/architecture/internals/indexing.md +1 -1
- package/docs/architecture/internals/search.md +1 -2
- package/docs/architecture/internals/storage-locations.md +6 -6
- package/docs/architecture/persisted-data-compat.md +13 -4
- package/docs/architecture/specs/0.9.0-decisions.md +6 -2
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +2 -2
- package/docs/architecture/specs/workflow-format-unification.md +1 -6
- package/docs/architecture/testing/manual-testing-checklist.md +21 -30
- package/docs/architecture/testing/task-workflow-manual-tests.md +106 -203
- package/docs/architecture/testing/testing-workflow.md +1 -1
- package/docs/architecture/workflow-engine.md +5 -56
- package/docs/guides/author-workflows.md +39 -69
- package/docs/guides/bundles.md +3 -1
- package/docs/guides/capture-knowledge.md +1 -1
- package/docs/guides/claude-code-vs-akm-workflows.md +1 -2
- package/docs/guides/discover-and-load.md +4 -4
- package/docs/guides/getting-started.md +1 -1
- package/docs/guides/improve-the-library.md +10 -9
- package/docs/guides/recipes/headless-install.md +2 -2
- package/docs/guides/run-workflows.md +1 -1
- package/docs/guides/scheduling.md +9 -1
- package/docs/guides/use-with-any-agent.md +49 -4
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/curate-workmap.md +1 -2
- package/docs/maintainers/release-checklist.md +33 -1
- package/docs/migration/README.md +2 -0
- package/docs/migration/release-notes/0.10.0.md +201 -0
- package/docs/migration/release-notes/README.md +1 -0
- package/docs/migration/v0.9-to-v0.10.md +507 -0
- package/docs/posts/akm-command-tour.md +3 -3
- package/docs/product-surface.md +1 -1
- package/docs/reference/README.md +1 -0
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +3 -5
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +160 -188
- package/docs/reference/configuration.md +101 -20
- package/docs/reference/data-and-telemetry.md +2 -2
- package/docs/reference/env-and-secrets.md +2 -2
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +1 -1
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +12 -2
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/improve/retrieval-gate.js +0 -132
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/indexer/feedback/utility-policy.js +0 -75
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- 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
|
|
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
|
|
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
|
|
32
|
-
const WORKFLOW_EXTS = new Set([".md"
|
|
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"
|
|
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(/\.
|
|
159
|
-
return /\.
|
|
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
|
|
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,
|
|
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
|
|
19
|
-
*
|
|
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
|
-
//
|
|
133
|
-
//
|
|
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:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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,
|
package/dist/core/common.js
CHANGED
|
@@ -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 =
|
|
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/
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
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
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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})
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* {@link resolveExtendsChain} (each base in the chain) so a
|
|
103
|
-
* config can carry its own `configVersion`
|
|
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
|
-
|
|
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
|
-
*
|
|
188
|
-
*
|
|
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
|
-
*
|
|
660
|
-
* `
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
import { HARNESS_AGENT_DISPATCH_IDS, HARNESS_NATIVE_AGENT_IDS, VALID_HARNESS_IDS, } from "../../../integrations/harnesses/
|
|
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
|
/**
|