akm-cli 0.10.261015-beta → 0.10.261017-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 +173 -0
- package/README.md +8 -10
- package/SECURITY.md +7 -99
- package/STABILITY.md +58 -98
- package/dist/assets/hints/cli-hints-full.md +6 -4
- package/dist/assets/hints/cli-hints-short.md +4 -2
- package/dist/assets/opencode/akm-plugin.js +16 -8
- package/dist/assets/prompts/workflow-unit-preamble.md +3 -1
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -2
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +11 -17
- package/dist/cli.js +32 -41
- package/dist/commands/feedback-cli.js +5 -4
- package/dist/commands/health/plugin-staleness.js +86 -22
- package/dist/commands/health.js +15 -16
- package/dist/commands/proposal/proposal-cli.js +1 -1
- package/dist/commands/read/registry-search.js +4 -1
- package/dist/commands/read/search-cli.js +2 -2
- package/dist/commands/read/search.js +6 -6
- package/dist/commands/read/show.js +15 -3
- package/dist/commands/sources/self-update.js +9 -5
- package/dist/commands/tasks/tasks.js +12 -13
- package/dist/core/adapter/adapters/agent-skills-adapter.js +7 -7
- package/dist/core/adapter/adapters/akm-task-adapter.js +1 -1
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
- package/dist/core/adapter/adapters/claude-adapter.js +1 -1
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +1 -1
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +1 -1
- package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -1
- package/dist/core/asset/markdown.js +9 -0
- package/dist/core/bundle-rename.js +17 -7
- package/dist/core/config/config-walker.js +35 -32
- package/dist/core/config/schema/connections.js +6 -3
- package/dist/core/config/schema/harnesses.js +8 -1
- package/dist/core/config/schema/primitives.js +12 -1
- package/dist/core/config/schema/sources-bundles.js +2 -2
- package/dist/core/npm-package.js +48 -13
- package/dist/indexer/bundle-identity-guard.js +6 -6
- package/dist/indexer/index-written-assets.js +3 -3
- package/dist/indexer/indexer.js +12 -8
- package/dist/indexer/materialize-embeddings.js +12 -2
- package/dist/indexer/passes/metadata.js +103 -46
- package/dist/indexer/search/ranking.js +7 -3
- package/dist/indexer/search/search-fields.js +1 -1
- package/dist/indexer/usage/usage-events.js +30 -8
- package/dist/indexer/walk/walker.js +1 -1
- package/dist/output/renderers.js +2 -2
- package/dist/output/shapes/helpers.js +5 -3
- package/dist/output/text/command-format.js +5 -6
- package/dist/output/text/show-format.js +7 -0
- package/dist/registry/semver.js +12 -0
- package/dist/scripts/akm-migrate-node.js +21653 -5734
- package/dist/scripts/akm-migrate.js +21661 -5742
- package/dist/sources/providers/git-provider.js +2 -4
- package/dist/sources/providers/provider-utils.js +8 -13
- package/dist/sources/snapshot-fetchers/website-ingest.js +6 -7
- package/dist/storage/repositories/events-repository.js +15 -0
- package/dist/storage/repositories/improve-ledger-repository.js +13 -0
- package/dist/storage/repositories/index-entries-repository.js +43 -5
- package/dist/storage/repositories/outcome-repository.js +12 -0
- package/dist/storage/repositories/proposals-repository.js +5 -5
- package/dist/storage/repositories/salience-repository.js +13 -0
- package/dist/storage/repositories/task-history-repository.js +8 -7
- package/dist/storage/repositories/workflow-runs-repository.js +10 -8
- package/dist/tasks/backends/cron.js +19 -0
- package/docs/README.md +24 -60
- package/docs/agents/README.md +3 -8
- package/docs/architecture/README.md +18 -20
- package/docs/architecture/adapters.md +40 -43
- package/docs/architecture/architecture.md +171 -151
- package/docs/architecture/improvement.md +95 -91
- package/docs/architecture/internals/classification.md +101 -119
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +33 -35
- package/docs/architecture/internals/health-advisories.md +59 -46
- package/docs/architecture/internals/improve-workflow.md +166 -693
- package/docs/architecture/internals/indexing.md +65 -465
- package/docs/architecture/internals/storage-locations.md +301 -848
- package/docs/architecture/persisted-data-compat.md +6 -6
- package/docs/architecture/specs/okf-support.md +67 -95
- package/docs/architecture/specs/ref.md +67 -124
- package/docs/architecture/testing/testing-workflow.md +114 -175
- package/docs/architecture/workflow-engine.md +34 -33
- package/docs/guides/README.md +5 -5
- package/docs/guides/author-bundles.md +72 -98
- package/docs/guides/author-workflows.md +11 -18
- package/docs/guides/bundles.md +91 -123
- package/docs/guides/capture-knowledge.md +10 -9
- package/docs/guides/concepts.md +45 -30
- package/docs/guides/discover-and-load.md +51 -36
- package/docs/guides/getting-started.md +27 -26
- package/docs/guides/improve-the-library.md +98 -80
- package/docs/guides/recipes/headless-install.md +4 -4
- package/docs/guides/recipes/website-source.md +9 -5
- package/docs/guides/run-workflows.md +10 -11
- package/docs/guides/scheduling.md +11 -17
- package/docs/guides/use-with-any-agent.md +15 -11
- package/docs/guides/wikis.md +6 -9
- package/docs/integration/bundling-akm.md +21 -26
- package/docs/maintainers/README.md +2 -2
- package/docs/maintainers/local-development.md +3 -16
- package/docs/maintainers/release-checklist.md +15 -8
- package/docs/migration/README.md +2 -1
- package/docs/migration/release-notes/0.10.0.md +167 -22
- package/docs/migration/release-notes/README.md +2 -2
- package/docs/migration/v0.9-to-v0.10.md +47 -7
- package/docs/product-surface.md +10 -8
- package/docs/reference/README.md +26 -15
- package/docs/reference/asset-types.md +11 -12
- package/docs/reference/bundle-types.md +6 -5
- package/docs/reference/cli.md +74 -31
- package/docs/reference/configuration.md +46 -60
- package/docs/reference/data-and-telemetry.md +204 -421
- package/docs/reference/env-and-secrets.md +80 -83
- package/docs/reference/memory.md +1 -1
- package/docs/reference/refs.md +23 -36
- package/docs/reference/registry.md +138 -348
- package/docs/reference/supported-formats.md +8 -8
- package/docs/reference/tasks.md +13 -19
- package/docs/reference/website-sources.md +23 -15
- package/docs/reference/workflow-schema.md +28 -47
- package/docs/reference/workflows.md +33 -37
- package/package.json +4 -4
- package/schemas/akm-config.json +535 -302
|
@@ -20,7 +20,7 @@ import { recognizeMatch } from "../../core/adapter/recognize-match.js";
|
|
|
20
20
|
import { assetPathForName, stashDirFor } from "../../core/asset/asset-placement.js";
|
|
21
21
|
import { makeBundleRef, parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
22
22
|
import { parseFrontmatter } from "../../core/asset/frontmatter.js";
|
|
23
|
-
import { extractSection, markdownFragmentSlugs } from "../../core/asset/markdown.js";
|
|
23
|
+
import { extractSection, markdownFragmentSlugs, markdownToc } from "../../core/asset/markdown.js";
|
|
24
24
|
import { buildMarkdownLeadContext, fragmentForSelector, MARKDOWN_FRAGMENT_CONTEXT_DEFAULT_MAX_CHARS, } from "../../core/asset/markdown-fragments.js";
|
|
25
25
|
import { displayRef, displayRefForConceptId, typeNameFromConceptId } from "../../core/asset/resolve-ref.js";
|
|
26
26
|
import { META_DIR, parseMetaRef, readMetaFile } from "../../core/asset/stash-meta.js";
|
|
@@ -297,8 +297,10 @@ export async function showLocal(input) {
|
|
|
297
297
|
const indexedFragmentContent = opaqueFragmentSelector ? indexedFragment?.content : undefined;
|
|
298
298
|
const indexedRenderer = rendererForIndexedEntry(indexedEntry, fileCtx);
|
|
299
299
|
let response;
|
|
300
|
+
let markdown = false;
|
|
300
301
|
try {
|
|
301
302
|
if (indexedRenderer === null) {
|
|
303
|
+
markdown = path.extname(assetPath).toLowerCase() === ".md";
|
|
302
304
|
response = buildIndexedProjectionResponse(indexedEntry, assetPath, parsed.fragment, indexedFragmentContent);
|
|
303
305
|
}
|
|
304
306
|
else {
|
|
@@ -315,8 +317,9 @@ export async function showLocal(input) {
|
|
|
315
317
|
const renderDefaultBundle = config.defaultBundle ?? (source?.isDefault === true ? renderBundle : undefined);
|
|
316
318
|
const renderCtx = buildRenderContext(fileCtx, match, allSourceDirs, renderBundle, renderDefaultBundle);
|
|
317
319
|
response = renderer.buildShowResponse(renderCtx);
|
|
320
|
+
markdown = match.renderer.endsWith("-md");
|
|
318
321
|
if (parsed.fragment !== undefined) {
|
|
319
|
-
if (!
|
|
322
|
+
if (!markdown) {
|
|
320
323
|
warn(`Fragment "#${parsed.fragment}" was ignored: ${makeBundleRef(parsed.bundle, parsed.conceptId)} is not a Markdown document, so heading fragments do not apply. Showing the whole asset.`);
|
|
321
324
|
}
|
|
322
325
|
else {
|
|
@@ -324,6 +327,13 @@ export async function showLocal(input) {
|
|
|
324
327
|
}
|
|
325
328
|
}
|
|
326
329
|
}
|
|
330
|
+
// The outline is read from the bytes `#<slug>` resolves against, so every
|
|
331
|
+
// listed slug selects its section even when the index is stale.
|
|
332
|
+
if (markdown && parsed.fragment === undefined) {
|
|
333
|
+
const toc = markdownToc(fileCtx.content());
|
|
334
|
+
if (toc.length > 0)
|
|
335
|
+
response.toc = toc;
|
|
336
|
+
}
|
|
327
337
|
}
|
|
328
338
|
catch (error) {
|
|
329
339
|
throwIndexedPathNotFound(error, input.ref);
|
|
@@ -598,6 +608,7 @@ function applyMarkdownResponsePayload(response, content) {
|
|
|
598
608
|
else
|
|
599
609
|
response.content = content;
|
|
600
610
|
}
|
|
611
|
+
const SHOW_OUTLINE_HINT = "Run `akm show <ref> --detail brief` for the document's outline (`toc`, no body), then `akm show <ref>#<slug>` for one section.";
|
|
601
612
|
function requireMarkdownSection(content, fragment, name) {
|
|
602
613
|
const section = extractSection(content, fragment);
|
|
603
614
|
if (section)
|
|
@@ -609,7 +620,7 @@ function requireMarkdownSection(content, fragment, name) {
|
|
|
609
620
|
}
|
|
610
621
|
const available = markdownFragmentSlugs(content);
|
|
611
622
|
throw new NotFoundError(`Fragment "#${fragment}" not found in ${name}.` +
|
|
612
|
-
(available.length > 0 ? ` Available fragments: ${available.map((slug) => `#${slug}`).join(", ")}.` : ""));
|
|
623
|
+
(available.length > 0 ? ` Available fragments: ${available.map((slug) => `#${slug}`).join(", ")}.` : ""), "ASSET_NOT_FOUND", SHOW_OUTLINE_HINT);
|
|
613
624
|
}
|
|
614
625
|
/**
|
|
615
626
|
* Build a reduced brief response from a full ShowResponse.
|
|
@@ -625,6 +636,7 @@ function buildBriefResponse(full, assetPath) {
|
|
|
625
636
|
...(summary.ref ? { ref: summary.ref } : {}),
|
|
626
637
|
...(summary.description ? { description: summary.description } : {}),
|
|
627
638
|
...(summary.action ? { action: summary.action } : {}),
|
|
639
|
+
...(full.toc ? { toc: full.toc } : {}),
|
|
628
640
|
...(summary.run ? { run: summary.run } : {}),
|
|
629
641
|
...(summary.origin !== undefined ? { origin: summary.origin } : {}),
|
|
630
642
|
...(full.editable !== undefined ? { editable: full.editable } : {}),
|
|
@@ -7,7 +7,7 @@ import fs from "node:fs";
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { fetchWithRetry, IS_WINDOWS, ResponseTooLargeError, readBodyWithByteCap, readChunkWithDeadline, } from "../../core/common.js";
|
|
9
9
|
import { ConfigError } from "../../core/errors.js";
|
|
10
|
-
import { warn } from "../../core/warn.js";
|
|
10
|
+
import { isQuiet, warn } from "../../core/warn.js";
|
|
11
11
|
import { githubHeaders } from "../../integrations/github.js";
|
|
12
12
|
import { getDirname, mainPath, semverOrder } from "../../runtime.js";
|
|
13
13
|
import { resolveNpmGlobalRoot } from "../../tasks/resolve-akm-bin.js";
|
|
@@ -428,7 +428,11 @@ async function runMigrationStep(runTool) {
|
|
|
428
428
|
return { status: "failed", error: result.stderr.trim() || line || `akm-migrate exited ${result.status}` };
|
|
429
429
|
}
|
|
430
430
|
/**
|
|
431
|
-
* Rebuild the derived index after a successful upgrade.
|
|
431
|
+
* Rebuild the derived index after a successful upgrade. The first index after
|
|
432
|
+
* an upgrade can re-embed part of the corpus and take minutes, so the child's
|
|
433
|
+
* stderr (its progress lines) goes straight to the terminal; its stdout, never a
|
|
434
|
+
* terminal here, is captured. `--format json` keeps the progress on stderr
|
|
435
|
+
* whatever output format the user has configured, and `--quiet` is passed on.
|
|
432
436
|
*/
|
|
433
437
|
function runPostUpgradeTasks(akmBin, opts) {
|
|
434
438
|
if (opts.skip) {
|
|
@@ -439,10 +443,10 @@ function runPostUpgradeTasks(akmBin, opts) {
|
|
|
439
443
|
};
|
|
440
444
|
}
|
|
441
445
|
try {
|
|
442
|
-
const result = childProcess.spawnSync(akmBin, ["index"], {
|
|
446
|
+
const result = childProcess.spawnSync(akmBin, ["index", "--format", "json", ...(isQuiet() ? ["--quiet"] : [])], {
|
|
443
447
|
encoding: "utf8",
|
|
444
448
|
env: process.env,
|
|
445
|
-
stdio: "pipe",
|
|
449
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
446
450
|
});
|
|
447
451
|
if (result.error) {
|
|
448
452
|
return {
|
|
@@ -452,7 +456,7 @@ function runPostUpgradeTasks(akmBin, opts) {
|
|
|
452
456
|
};
|
|
453
457
|
}
|
|
454
458
|
if (result.status !== 0) {
|
|
455
|
-
const detail = (result.
|
|
459
|
+
const detail = (result.stdout ?? "").trim() || `exit code ${result.status}`;
|
|
456
460
|
return {
|
|
457
461
|
ok: false,
|
|
458
462
|
skipped: false,
|
|
@@ -178,10 +178,10 @@ export async function akmTasksRun(id, options = {}) {
|
|
|
178
178
|
const adapterId = bundle.source.adapterId ?? detectAdapterId(bundle.source.path);
|
|
179
179
|
const resolvedId = taskIdForAdapter(parsed.id, adapterId);
|
|
180
180
|
const scheduled = options.scheduled === true;
|
|
181
|
-
// Built ONCE at this invocation boundary. eventSource is "task"
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
181
|
+
// Built ONCE at this invocation boundary. eventSource is "task" whether or
|
|
182
|
+
// not --scheduled was passed — scheduled stays a separate field carrying its
|
|
183
|
+
// own meaning (activation policy, scheduler env), never selecting the event
|
|
184
|
+
// source.
|
|
185
185
|
const provenance = createExecutionProvenanceContext(scheduled);
|
|
186
186
|
// The raw, exact-name input flags `tasks-cli.ts`'s Stage 1 captures ride
|
|
187
187
|
// through unchanged to `runTask` -> `loadPreparedTask`'s Stage 2 materializer,
|
|
@@ -206,8 +206,8 @@ export async function akmTasksRun(id, options = {}) {
|
|
|
206
206
|
// projectability, and resolver failures therefore create no history row.
|
|
207
207
|
const result = await runTask(resolvedId, runOptions);
|
|
208
208
|
// "command" means the agent/LLM arm — the native shell/script arm reports
|
|
209
|
-
// "shell" / "script"
|
|
210
|
-
//
|
|
209
|
+
// "shell" / "script". A shell/script task's process exit 78 passes through
|
|
210
|
+
// as CLI exit 78 (documented behavior, src/assets/hints/cli-hints-short.md).
|
|
211
211
|
const exitCode = result.status === "failed" &&
|
|
212
212
|
(result.target.kind === "shell" || result.target.kind === "script") &&
|
|
213
213
|
result.detail?.exitCode === 78
|
|
@@ -597,10 +597,9 @@ export async function akmTasksDoctor(deps = {}) {
|
|
|
597
597
|
const config = loadConfig();
|
|
598
598
|
const defaultEngine = (defaultHarness(config) ?? defaultConnection(config))?.name;
|
|
599
599
|
const engines = [...Object.keys(config.connections ?? {}), ...Object.keys(config.harnesses ?? {})];
|
|
600
|
-
//
|
|
601
|
-
// strategy. The struct is a fixed shape, so this is a deliberate addition.
|
|
600
|
+
// Surface the effective triage settings for the default improve strategy.
|
|
602
601
|
const improveStrategyName = config.improve?.strategy ?? "default";
|
|
603
|
-
//
|
|
602
|
+
// Report the EFFECTIVE strategy, not the raw one. Resolving the raw
|
|
604
603
|
// strategy here would report `applyMode: "promote"` for a promote strategy
|
|
605
604
|
// under a review-first config, while the run actually uses "queue" — a doctor
|
|
606
605
|
// command lying about the thing it exists to diagnose.
|
|
@@ -753,7 +752,7 @@ function errorMessage(cause) {
|
|
|
753
752
|
}
|
|
754
753
|
/**
|
|
755
754
|
* Infer a JSON-Schema-subset `type` keyword from one `--params` value's
|
|
756
|
-
* runtime shape. `null` is not one of the five runtime types
|
|
755
|
+
* runtime shape. `null` is not one of the five usual runtime types
|
|
757
756
|
* (string/number/boolean/object/array) but is a value JSON.parse can still
|
|
758
757
|
* produce for a param; `src/core/json-schema.ts`'s subset validator accepts
|
|
759
758
|
* `"null"` as a `type`, so it is handled rather than mis-typed.
|
|
@@ -768,9 +767,9 @@ function jsonSchemaTypeOf(value) {
|
|
|
768
767
|
/**
|
|
769
768
|
* Render `--params` as typed `inputs:` declarations, one per key, each
|
|
770
769
|
* carrying a `default:` equal to the authored value and a `type:` inferred
|
|
771
|
-
* from its own JSON runtime shape
|
|
772
|
-
* task source v4 accepts `with:` only on `uses: akm/command`
|
|
773
|
-
* `parseTarget`/`checkTopLevelKeys`), and a workflow target's declared
|
|
770
|
+
* from its own JSON runtime shape. Never emitted as `with:` —
|
|
771
|
+
* task source v4 accepts `with:` only on `uses: akm/command`
|
|
772
|
+
* (`parseTarget`/`checkTopLevelKeys`), and a workflow target's declared
|
|
774
773
|
* inputs are what `load-task.ts`'s existing v4 delivery override binds into
|
|
775
774
|
* the child run's params.
|
|
776
775
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* The `agent-skills` adapter
|
|
5
|
+
* The `agent-skills` adapter.
|
|
6
6
|
*
|
|
7
7
|
* Recognizes a COLLECTION of standalone SKILL.md packages (like
|
|
8
8
|
* github.com/anthropics/skills): each `<name>/SKILL.md` is one `skill` item
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*
|
|
39
39
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
40
40
|
* `tests/fixtures/bundles/agent-skills/` + goldens
|
|
41
|
-
* `tests/fixtures/format-family-goldens/agent-skills/{recognition,
|
|
41
|
+
* `tests/fixtures/format-family-goldens/agent-skills/{recognition,lint,renderer}.json`.
|
|
42
42
|
*/
|
|
43
43
|
import fs from "node:fs";
|
|
44
44
|
import path from "node:path";
|
|
@@ -52,7 +52,7 @@ const SKILL_MANIFEST = "SKILL.md";
|
|
|
52
52
|
/** Agent Skills hard limits. */
|
|
53
53
|
const NAME_MAX = 64;
|
|
54
54
|
const DESCRIPTION_MAX = 1024;
|
|
55
|
-
/** Agent Skills reserved words a name must not contain
|
|
55
|
+
/** Agent Skills reserved words a name must not contain. */
|
|
56
56
|
const RESERVED_NAME_WORDS = ["anthropic", "claude"];
|
|
57
57
|
/** name charset/shape rule. */
|
|
58
58
|
const NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
@@ -98,7 +98,7 @@ function recognize(c, file) {
|
|
|
98
98
|
doc.tags = tags;
|
|
99
99
|
return doc;
|
|
100
100
|
}
|
|
101
|
-
/** The Agent Skills
|
|
101
|
+
/** The Agent Skills hard-rule checks for one SKILL.md (name + description). */
|
|
102
102
|
function skillFieldDiagnostics(relPath, dirName, data) {
|
|
103
103
|
const diagnostics = [];
|
|
104
104
|
const name = typeof data.name === "string" ? data.name.normalize("NFKC") : "";
|
|
@@ -176,8 +176,8 @@ async function scanPackageCandidate(dir, entries, ctx, depth) {
|
|
|
176
176
|
*
|
|
177
177
|
* `validate` walks CHANGES, and a change is always a file — so a package
|
|
178
178
|
* directory carrying resources but no manifest contributes nothing the
|
|
179
|
-
* change-loop can see, and the check the
|
|
180
|
-
*
|
|
179
|
+
* change-loop can see, and the check the lint golden's `missingSkillMd` edge
|
|
180
|
+
* case names would be unreachable. This scans the
|
|
181
181
|
* component root through {@link ValidateContext.list} instead, so the case is
|
|
182
182
|
* actually reported.
|
|
183
183
|
*
|
|
@@ -230,7 +230,7 @@ export const agentSkillsAdapter = {
|
|
|
230
230
|
readCandidates(c, conceptId) {
|
|
231
231
|
return [{ path: path.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
|
|
232
232
|
},
|
|
233
|
-
/** Install-time probe
|
|
233
|
+
/** Install-time probe: a root that directly contains one or more `<name>/SKILL.md` skill packages. */
|
|
234
234
|
looksLikeRoot(root) {
|
|
235
235
|
let entries;
|
|
236
236
|
try {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
28
28
|
* `tests/fixtures/bundles/akm-task/` + goldens
|
|
29
|
-
* `tests/fixtures/format-family-goldens/akm-task/{recognition,
|
|
29
|
+
* `tests/fixtures/format-family-goldens/akm-task/{recognition,lint,renderer}.json`.
|
|
30
30
|
*/
|
|
31
31
|
import fs from "node:fs";
|
|
32
32
|
import path from "node:path";
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
17
17
|
* `tests/fixtures/bundles/akm-workflow/` + goldens
|
|
18
|
-
* `tests/fixtures/format-family-goldens/akm-workflow/{recognition,
|
|
18
|
+
* `tests/fixtures/format-family-goldens/akm-workflow/{recognition,lint,renderer}.json`.
|
|
19
19
|
*/
|
|
20
20
|
import fs from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
18
18
|
* `tests/fixtures/bundles/claude/` + goldens
|
|
19
|
-
* `tests/fixtures/format-family-goldens/claude/{recognition,
|
|
19
|
+
* `tests/fixtures/format-family-goldens/claude/{recognition,lint,renderer}.json`.
|
|
20
20
|
*/
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import path from "node:path";
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*
|
|
26
26
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
27
27
|
* `tests/fixtures/bundles/dotenv/` + goldens
|
|
28
|
-
* `tests/fixtures/format-family-goldens/dotenv/{recognition,
|
|
28
|
+
* `tests/fixtures/format-family-goldens/dotenv/{recognition,lint,renderer}.json`.
|
|
29
29
|
*/
|
|
30
30
|
import fs from "node:fs";
|
|
31
31
|
import path from "node:path";
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
21
21
|
* `tests/fixtures/bundles/generic-files/` + goldens
|
|
22
|
-
* `tests/fixtures/format-family-goldens/generic-files/{recognition,
|
|
22
|
+
* `tests/fixtures/format-family-goldens/generic-files/{recognition,lint,renderer}.json`.
|
|
23
23
|
*/
|
|
24
24
|
import path from "node:path";
|
|
25
25
|
import { parseFrontmatter } from "../../asset/frontmatter.js";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
13
13
|
* `tests/fixtures/bundles/llm-wiki/` + goldens
|
|
14
|
-
* `tests/fixtures/format-family-goldens/llm-wiki/{recognition,
|
|
14
|
+
* `tests/fixtures/format-family-goldens/llm-wiki/{recognition,renderer,lint}.json`.
|
|
15
15
|
* The adapter is built to MATCH those goldens (driven by
|
|
16
16
|
* `tests/core/adapter/llm-wiki-adapter.test.ts`).
|
|
17
17
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
18
18
|
* `tests/fixtures/bundles/opencode/` + goldens
|
|
19
|
-
* `tests/fixtures/format-family-goldens/opencode/{recognition,
|
|
19
|
+
* `tests/fixtures/format-family-goldens/opencode/{recognition,lint,renderer}.json`.
|
|
20
20
|
*/
|
|
21
21
|
import fs from "node:fs";
|
|
22
22
|
import path from "node:path";
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* Conformance oracle (authored, DO NOT modify): fixture
|
|
24
24
|
* `tests/fixtures/bundles/website-snapshot/` + goldens
|
|
25
|
-
* `tests/fixtures/format-family-goldens/website-snapshot/{recognition,
|
|
25
|
+
* `tests/fixtures/format-family-goldens/website-snapshot/{recognition,lint,renderer}.json`.
|
|
26
26
|
*/
|
|
27
27
|
import fs from "node:fs";
|
|
28
28
|
import path from "node:path";
|
|
@@ -16,6 +16,15 @@ export function markdownHeadingSlug(heading) {
|
|
|
16
16
|
export function markdownFragmentSlugs(content) {
|
|
17
17
|
return uniqueHeadingSlugs(parseMarkdownToc(content).headings).filter(Boolean);
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The headings `extractSection` can select, with the slug it resolves each by.
|
|
21
|
+
* A heading with no sluggable text has no selector, so it is left out.
|
|
22
|
+
*/
|
|
23
|
+
export function markdownToc(content) {
|
|
24
|
+
const headings = parseMarkdownToc(content).headings;
|
|
25
|
+
const slugs = uniqueHeadingSlugs(headings);
|
|
26
|
+
return headings.flatMap((heading, index) => slugs[index] ? [{ level: heading.level, text: heading.text, slug: slugs[index], startLine: heading.line }] : []);
|
|
27
|
+
}
|
|
19
28
|
/** One slug per heading, in order; a heading with no sluggable text gets "". */
|
|
20
29
|
export function uniqueHeadingSlugs(headings) {
|
|
21
30
|
const used = new Set();
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* bundle's key. A bundle id is a mass identity prefix: every durable ref this
|
|
7
7
|
* tool minted (`entries.item_ref`/`bundle_id`, `proposals.ref`, a pending
|
|
8
8
|
* proposal's `proposedTarget.source`, a workflow task_history row's
|
|
9
|
-
* `target_ref`, a `workflow_runs.workflow_ref`, `
|
|
9
|
+
* `target_ref`, a `workflow_runs.workflow_ref`, a `usage_events.entry_ref`, an
|
|
10
|
+
* `events.ref`, an `asset_salience`/`asset_outcome` `asset_ref`, an
|
|
11
|
+
* `improve_ledger.ref`, `scheduler.enabled[].ref`) carries it, and a hand-edited
|
|
10
12
|
* `bundles` key strands all of it (see `src/indexer/bundle-identity-guard.ts`
|
|
11
13
|
* §11.5). This module is the rekey transaction that guard's docstring points
|
|
12
14
|
* to.
|
|
@@ -20,17 +22,17 @@
|
|
|
20
22
|
* `akm mv`/editing territory, not a config-identity rename. `--dry-run`
|
|
21
23
|
* (and every real run) lists the indexed files that still spell the old
|
|
22
24
|
* `<old>//` prefix so the operator can follow up.
|
|
23
|
-
*
|
|
24
|
-
* Left behind on purpose: `usage_events`/`asset_salience`/`asset_outcome`
|
|
25
|
-
* keyed by the old bundle prefix (learned utility/outcome history) — outside
|
|
26
|
-
* this item's scope; `warnOnBundleRenameDrift` already documents this class
|
|
27
|
-
* of gap and `akm index --full` re-mints under the new id.
|
|
28
25
|
*/
|
|
29
26
|
import fs from "node:fs";
|
|
27
|
+
import { renameUsageEventRefs } from "../indexer/usage/usage-events.js";
|
|
30
28
|
import { readLockfile, renameLockEntry } from "../integrations/lockfile.js";
|
|
29
|
+
import { renameEventRefs } from "../storage/repositories/events-repository.js";
|
|
30
|
+
import { renameImproveLedgerRefs } from "../storage/repositories/improve-ledger-repository.js";
|
|
31
31
|
import { closeDatabase, openIndexDatabase, openReadonlyExistingDatabase, } from "../storage/repositories/index-connection.js";
|
|
32
32
|
import { getFilePathsByBundle, renameEntriesBundleId } from "../storage/repositories/index-entries-repository.js";
|
|
33
|
+
import { renameAssetOutcomeRefs } from "../storage/repositories/outcome-repository.js";
|
|
33
34
|
import { countProposalsForBundleRename, renameProposalsBundleRef } from "../storage/repositories/proposals-repository.js";
|
|
35
|
+
import { renameAssetSalienceRefs } from "../storage/repositories/salience-repository.js";
|
|
34
36
|
import { countTaskHistoryTargetRefs, renameTaskHistoryTargetRefs, } from "../storage/repositories/task-history-repository.js";
|
|
35
37
|
import { countWorkflowRunRefsForRename, renameWorkflowRunRefs } from "../storage/repositories/workflow-runs-repository.js";
|
|
36
38
|
import { selectBackend } from "../tasks/backends/index.js";
|
|
@@ -262,12 +264,20 @@ export async function renameBundle(oldId, newId, options = {}, deps) {
|
|
|
262
264
|
}
|
|
263
265
|
}
|
|
264
266
|
// State: proposals.ref, a pending proposal's proposedTarget.source,
|
|
265
|
-
// workflow task_history.target_ref,
|
|
267
|
+
// workflow task_history.target_ref, workflow_runs.workflow_ref, and the
|
|
268
|
+
// learned history keyed by item ref: usage_events.entry_ref (search ranking
|
|
269
|
+
// counts feedback by it), events.ref and improve_ledger.ref (improve reads
|
|
270
|
+
// feedback and its own attempts by them), and asset_salience/asset_outcome.asset_ref.
|
|
266
271
|
if (fs.existsSync(getStateDbPath())) {
|
|
267
272
|
withStateDb((db) => {
|
|
268
273
|
renameProposalsBundleRef(db, oldId, newId);
|
|
269
274
|
renameTaskHistoryTargetRefs(db, oldId, newId);
|
|
270
275
|
renameWorkflowRunRefs(db, oldId, newId);
|
|
276
|
+
renameUsageEventRefs(db, oldId, newId);
|
|
277
|
+
renameEventRefs(db, oldId, newId);
|
|
278
|
+
renameImproveLedgerRefs(db, oldId, newId);
|
|
279
|
+
renameAssetSalienceRefs(db, oldId, newId);
|
|
280
|
+
renameAssetOutcomeRefs(db, oldId, newId);
|
|
271
281
|
});
|
|
272
282
|
}
|
|
273
283
|
// Scheduler: remove native rows still naming `<old>//` (see
|
|
@@ -27,7 +27,7 @@ import { hasRegistryUrlCredentials, REGISTRY_CREDENTIALS_UNSUPPORTED } from "../
|
|
|
27
27
|
import { warnOnce } from "../warn.js";
|
|
28
28
|
import { AkmConfigBaseSchema, listTopLevelConfigKeys } from "./config-schema.js";
|
|
29
29
|
import { deepMergeConfig } from "./deep-merge.js";
|
|
30
|
-
import { isEnvReference } from "./schema/primitives.js";
|
|
30
|
+
import { isEnvReference, OpaqueFieldSchema } from "./schema/primitives.js";
|
|
31
31
|
/**
|
|
32
32
|
* Parse a dotted path into segments. Empty segments are rejected. Bracket
|
|
33
33
|
* notation (e.g. `sources[0]`) is NOT supported — arrays are set as JSON.
|
|
@@ -46,33 +46,39 @@ function parsePath(dotted) {
|
|
|
46
46
|
function unwrap(schema) {
|
|
47
47
|
let current = schema;
|
|
48
48
|
while (true) {
|
|
49
|
-
if (current instanceof z.ZodOptional
|
|
50
|
-
current
|
|
51
|
-
|
|
52
|
-
else if (current instanceof z.ZodDefault) {
|
|
53
|
-
current = current._def.innerType;
|
|
54
|
-
}
|
|
55
|
-
else if (current instanceof z.ZodNullable) {
|
|
56
|
-
current = current._def.innerType;
|
|
57
|
-
}
|
|
58
|
-
else if (current instanceof z.ZodCatch) {
|
|
49
|
+
if (current instanceof z.ZodOptional ||
|
|
50
|
+
current instanceof z.ZodDefault ||
|
|
51
|
+
current instanceof z.ZodNullable ||
|
|
59
52
|
// `.catch(...)` wraps an inner schema with a fallback value.
|
|
60
|
-
current
|
|
53
|
+
current instanceof z.ZodCatch ||
|
|
54
|
+
current instanceof z.ZodReadonly) {
|
|
55
|
+
current = current.def.innerType;
|
|
61
56
|
}
|
|
62
|
-
else if (current instanceof z.
|
|
63
|
-
// `.
|
|
64
|
-
// descend into the
|
|
65
|
-
|
|
66
|
-
current =
|
|
67
|
-
}
|
|
68
|
-
else if (current instanceof z.ZodReadonly) {
|
|
69
|
-
current = current._def.innerType;
|
|
57
|
+
else if (current instanceof z.ZodPipe) {
|
|
58
|
+
// `.transform()` pipes the schema into a transform and `z.preprocess()` pipes a transform into it:
|
|
59
|
+
// descend into the side that is a schema. (`.refine()` and `.superRefine()` wrap nothing.)
|
|
60
|
+
const { in: input, out } = current.def;
|
|
61
|
+
current = (input instanceof z.ZodTransform ? out : input);
|
|
70
62
|
}
|
|
71
63
|
else {
|
|
72
64
|
return current;
|
|
73
65
|
}
|
|
74
66
|
}
|
|
75
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* The schema of the keys an object takes without naming them (`index.<passName>`,
|
|
70
|
+
* a connection's request fields), or `undefined` when its extra keys are not
|
|
71
|
+
* ones akm defines. `.passthrough()` gives an object an `unknown` catchall, so
|
|
72
|
+
* only `OpaqueFieldSchema` itself says "any key, contents left to the endpoint".
|
|
73
|
+
*/
|
|
74
|
+
function namedCatchall(object) {
|
|
75
|
+
const catchall = object.def.catchall;
|
|
76
|
+
if (catchall === undefined || catchall instanceof z.ZodNever)
|
|
77
|
+
return undefined;
|
|
78
|
+
if (catchall instanceof z.ZodUnknown && catchall !== OpaqueFieldSchema)
|
|
79
|
+
return undefined;
|
|
80
|
+
return catchall;
|
|
81
|
+
}
|
|
76
82
|
/** True for a schema that accepts any value (`z.unknown()`): its contents are not keys akm defines. */
|
|
77
83
|
export function isOpaqueSchema(schema) {
|
|
78
84
|
return unwrap(schema) instanceof z.ZodUnknown;
|
|
@@ -91,13 +97,10 @@ export function resolveSchemaAt(path, config, raw) {
|
|
|
91
97
|
const next = schema.shape[segment];
|
|
92
98
|
if (!next) {
|
|
93
99
|
// Catchall (e.g. index.<passName>) — descend into the catchall schema.
|
|
94
|
-
const catchall = schema
|
|
95
|
-
if (
|
|
96
|
-
schema = catchall;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
100
|
+
const catchall = namedCatchall(schema);
|
|
101
|
+
if (!catchall)
|
|
99
102
|
return undefined;
|
|
100
|
-
|
|
103
|
+
schema = catchall;
|
|
101
104
|
}
|
|
102
105
|
else {
|
|
103
106
|
schema = next;
|
|
@@ -106,13 +109,13 @@ export function resolveSchemaAt(path, config, raw) {
|
|
|
106
109
|
else if (schema instanceof z.ZodRecord) {
|
|
107
110
|
// Named records (connections, harnesses, improve.strategies, sources, etc.)
|
|
108
111
|
// accept any string key — descend into the value schema.
|
|
109
|
-
schema = schema.
|
|
112
|
+
schema = schema.def.valueType;
|
|
110
113
|
}
|
|
111
114
|
else if (schema instanceof z.ZodUnion) {
|
|
112
|
-
const option = selectUnionObjectOption(schema.
|
|
115
|
+
const option = selectUnionObjectOption(schema.options, segment, existing, index === path.length - 1 ? raw : undefined);
|
|
113
116
|
if (!option)
|
|
114
117
|
return undefined;
|
|
115
|
-
schema = (option.shape[segment] ?? option
|
|
118
|
+
schema = (option.shape[segment] ?? namedCatchall(option));
|
|
116
119
|
}
|
|
117
120
|
else {
|
|
118
121
|
// Cannot descend into a non-object schema.
|
|
@@ -145,7 +148,7 @@ function selectUnionObjectOption(candidates, segment, existing, raw) {
|
|
|
145
148
|
}
|
|
146
149
|
return (options.find((option) => segment in option.shape) ??
|
|
147
150
|
// A model entry such as `{ model, reasoning_effort }` holds request fields the object does not name.
|
|
148
|
-
options.find((option) =>
|
|
151
|
+
options.find((option) => namedCatchall(option) !== undefined));
|
|
149
152
|
}
|
|
150
153
|
/**
|
|
151
154
|
* Get the value at the dotted path from a config-shaped object. Returns
|
|
@@ -350,7 +353,7 @@ function coerceForSchema(schema, raw, key) {
|
|
|
350
353
|
return raw;
|
|
351
354
|
}
|
|
352
355
|
if (target instanceof z.ZodLiteral) {
|
|
353
|
-
return typeof target.
|
|
356
|
+
return typeof target.value === "string" ? raw : target.value;
|
|
354
357
|
}
|
|
355
358
|
if (target instanceof z.ZodArray || target instanceof z.ZodObject || target instanceof z.ZodRecord) {
|
|
356
359
|
if (raw === "" || raw === "null")
|
|
@@ -366,7 +369,7 @@ function coerceForSchema(schema, raw, key) {
|
|
|
366
369
|
if (target instanceof z.ZodUnion) {
|
|
367
370
|
// Try each option in order. Use the first that the schema accepts after
|
|
368
371
|
// coercion. Falls through to JSON parsing if all fail.
|
|
369
|
-
const options = target.
|
|
372
|
+
const options = target.options;
|
|
370
373
|
let lastErr;
|
|
371
374
|
for (const opt of options) {
|
|
372
375
|
try {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import { WORKFLOW_MAX_TIMEOUT_MS } from "../../../workflows/resource-limits.js";
|
|
15
|
-
import { connectionEndpoint, engineName, envReferenceApiKey, nonEmptyString, positiveInt, retiredApiKeyFile, } from "./primitives.js";
|
|
15
|
+
import { connectionEndpoint, engineName, envReferenceApiKey, nonEmptyString, OpaqueFieldSchema, positiveInt, retiredApiKeyFile, } from "./primitives.js";
|
|
16
16
|
/**
|
|
17
17
|
* Timeouts share the workflow ceiling: a larger value would pass config
|
|
18
18
|
* validation and then fail every run with an unlocated "invocation is invalid".
|
|
@@ -24,7 +24,10 @@ export const timeoutMsField = z.union([positiveInt.max(WORKFLOW_MAX_TIMEOUT_MS),
|
|
|
24
24
|
* request fields of its own. The object is listed first so a JSON value given to
|
|
25
25
|
* `akm config set` is read as one.
|
|
26
26
|
*/
|
|
27
|
-
export const ModelEntrySchema = z.union([
|
|
27
|
+
export const ModelEntrySchema = z.union([
|
|
28
|
+
z.object({ model: nonEmptyString }).catchall(OpaqueFieldSchema),
|
|
29
|
+
nonEmptyString,
|
|
30
|
+
]);
|
|
28
31
|
/** Alias (`fast`, `balanced`, `reasoning`, or any the user adds) to the model it names. */
|
|
29
32
|
export const ModelAliasesSchema = z.record(nonEmptyString, ModelEntrySchema);
|
|
30
33
|
export const ConnectionSchema = z
|
|
@@ -37,5 +40,5 @@ export const ConnectionSchema = z
|
|
|
37
40
|
timeoutMs: timeoutMsField,
|
|
38
41
|
concurrency: positiveInt.optional(),
|
|
39
42
|
})
|
|
40
|
-
.catchall(
|
|
43
|
+
.catchall(OpaqueFieldSchema);
|
|
41
44
|
export const ConnectionsSchema = z.record(engineName, ConnectionSchema);
|
|
@@ -13,7 +13,14 @@ import { ModelAliasesSchema, timeoutMsField } from "./connections.js";
|
|
|
13
13
|
import { engineName, nonEmptyString } from "./primitives.js";
|
|
14
14
|
export const HarnessSchema = z
|
|
15
15
|
.object({
|
|
16
|
-
|
|
16
|
+
// Zod 4's message for a value outside an enum no longer quotes the value; the warning for a dropped harness should.
|
|
17
|
+
platform: z
|
|
18
|
+
.enum(HARNESS_CONFIG_PLATFORMS, {
|
|
19
|
+
error: (issue) => issue.code === "invalid_value"
|
|
20
|
+
? `${JSON.stringify(issue.input)} is not one of ${HARNESS_CONFIG_PLATFORMS.join(", ")}`
|
|
21
|
+
: undefined,
|
|
22
|
+
})
|
|
23
|
+
.optional(),
|
|
17
24
|
bin: nonEmptyString.optional(),
|
|
18
25
|
args: z.array(z.string()).optional(),
|
|
19
26
|
workspace: nonEmptyString.optional(),
|
|
@@ -12,11 +12,22 @@ import { redactUrlCredentials } from "../../redaction.js";
|
|
|
12
12
|
import { isSecretRefToken } from "../../ref-token.js";
|
|
13
13
|
import { warnOnce } from "../../warn.js";
|
|
14
14
|
import { ENGINE_NAME_PATTERN_SOURCE } from "../engine-semantics.js";
|
|
15
|
+
// Zod 4 reports a map key its key schema rejects as "Invalid key in record" and keeps that schema's own message
|
|
16
|
+
// (the naming rule, the slug rule) inside the issue; config errors and warnings print only the outer message.
|
|
17
|
+
z.config({
|
|
18
|
+
customError: (issue) => issue.code === "invalid_key" ? issue.issues.map((inner) => inner.message).join("; ") : undefined,
|
|
19
|
+
});
|
|
15
20
|
/** Persisted config schema version. Package prerelease/patch versions do not change this value. */
|
|
16
21
|
export const CURRENT_CONFIG_VERSION = "0.9.0";
|
|
17
22
|
// ── Reusable atomic schemas ─────────────────────────────────────────────────
|
|
18
23
|
/** Positive integer (used for tokens, timeouts, batch sizes). */
|
|
19
24
|
export const positiveInt = z.number().int().positive();
|
|
25
|
+
/**
|
|
26
|
+
* The catchall of an object whose extra keys are the endpoint's to define (a connection's request fields):
|
|
27
|
+
* any key, contents left alone. The config walker knows it by identity: a `.passthrough()` object also has an
|
|
28
|
+
* `unknown` catchall, and its extra keys are ones akm does not define.
|
|
29
|
+
*/
|
|
30
|
+
export const OpaqueFieldSchema = z.unknown();
|
|
20
31
|
/** Non-negative finite number (used for scores, weights, days). */
|
|
21
32
|
export const nonNegativeNumber = z.number().finite().min(0);
|
|
22
33
|
/** Non-empty string (rejects "" and whitespace-only). */
|
|
@@ -92,7 +103,7 @@ export const connectionEndpoint = z.string().superRefine((value, ctx) => {
|
|
|
92
103
|
warnOnce(`connectionEndpoint:userinfo:${shown}`, `Config endpoint "${shown}" embeds a username/password; move the credential out of the URL (apiKey: "$VAR", or credentials.json).`);
|
|
93
104
|
}
|
|
94
105
|
});
|
|
95
|
-
export const ExtraParamsSchema = z.record(z.unknown()).superRefine((value, ctx) => {
|
|
106
|
+
export const ExtraParamsSchema = z.record(z.string(), z.unknown()).superRefine((value, ctx) => {
|
|
96
107
|
for (const issue of validateExtraParams(value)) {
|
|
97
108
|
ctx.addIssue({ code: z.ZodIssueCode.custom, path: issue.path, message: issue.message });
|
|
98
109
|
}
|
|
@@ -16,7 +16,7 @@ import { isBundleSlug } from "../../asset/asset-ref.js";
|
|
|
16
16
|
import { httpUrl, isApiKeyReference, nonEmptyString, positiveInt } from "./primitives.js";
|
|
17
17
|
const VALID_ADAPTER_IDS_SET = new Set(VALID_ADAPTER_IDS);
|
|
18
18
|
// ── Sources / registries / installed ────────────────────────────────────────
|
|
19
|
-
const SourceConfigEntryOptionsSchema = z.record(z.unknown());
|
|
19
|
+
const SourceConfigEntryOptionsSchema = z.record(z.string(), z.unknown());
|
|
20
20
|
export const SourceConfigEntrySchema = z
|
|
21
21
|
.object({
|
|
22
22
|
type: nonEmptyString,
|
|
@@ -74,7 +74,7 @@ export const RegistryConfigEntrySchema = z
|
|
|
74
74
|
name: z.string().min(1).optional(),
|
|
75
75
|
enabled: z.boolean().optional(),
|
|
76
76
|
provider: z.string().min(1).optional(),
|
|
77
|
-
options: z.record(z.unknown()).optional(),
|
|
77
|
+
options: z.record(z.string(), z.unknown()).optional(),
|
|
78
78
|
})
|
|
79
79
|
.passthrough();
|
|
80
80
|
// ── Bundles ─────────────────────────────────────────────────────────────────
|