@canonical/pragma-cli 0.33.0 → 0.34.0
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/README.md +7 -7
- package/dist/pragma +0 -0
- package/package.json +18 -15
- package/pragma.conf.ts +664 -0
- package/src/bin.ts +13 -4
- package/src/capabilities/block.parity.test.ts +250 -0
- package/src/capabilities/capabilities/capabilities.render.ts +3 -2
- package/src/capabilities/capabilities/capabilities.verb.ts +31 -13
- package/src/capabilities/capabilities/catalog.ts +18 -10
- package/src/capabilities/capabilities/hints.ts +13 -19
- package/src/capabilities/colophon/collectColophon.ts +34 -19
- package/src/capabilities/colophon/colophon.verb.ts +8 -4
- package/src/capabilities/colophon/types.ts +16 -7
- package/src/capabilities/config/collectConfigShow.test.ts +57 -0
- package/src/capabilities/config/collectConfigShow.ts +41 -4
- package/src/capabilities/config/fields.ts +0 -27
- package/src/capabilities/config/set.verb.ts +7 -3
- package/src/capabilities/config/show.render.test.ts +77 -5
- package/src/capabilities/config/show.render.ts +7 -12
- package/src/capabilities/config/show.verb.ts +4 -3
- package/src/capabilities/config/types.ts +8 -0
- package/src/capabilities/create/byteEquality.test.ts +78 -100
- package/src/capabilities/create/compiledCreate.subprocess.test.ts +52 -15
- package/src/capabilities/create/constants.ts +75 -0
- package/src/capabilities/create/create.mcp.test.ts +2 -2
- package/src/capabilities/create/create.test.ts +162 -15
- package/src/capabilities/create/create.verb.ts +140 -69
- package/src/capabilities/create/index.ts +2 -10
- package/src/capabilities/create/pickGenerator.ts +34 -28
- package/src/capabilities/create/templates.embedded.generated.ts +4 -29
- package/src/capabilities/create/types.ts +10 -6
- package/src/capabilities/{standard/parity.test.ts → distribution.parity.test.ts} +24 -14
- package/src/capabilities/distribution.test.ts +120 -0
- package/src/capabilities/distribution.ts +59 -0
- package/src/capabilities/doctor/checks/checkConfigFile.ts +6 -5
- package/src/capabilities/doctor/checks/checkKeStore.ts +2 -2
- package/src/capabilities/doctor/checks/checkMcpConfigured.ts +7 -6
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +79 -45
- package/src/capabilities/doctor/checks/checkPragmaVersion.ts +3 -2
- package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +61 -11
- package/src/capabilities/doctor/checks/checkShellCompletions.ts +63 -23
- package/src/capabilities/doctor/checks/checkSkillsSymlinked.ts +3 -2
- package/src/capabilities/doctor/doctor.render.test.ts +6 -6
- package/src/capabilities/doctor/doctor.render.ts +2 -1
- package/src/capabilities/doctor/doctor.test.ts +37 -8
- package/src/capabilities/doctor/doctor.verb.ts +6 -2
- package/src/capabilities/doctor/runChecks.ts +5 -5
- package/src/capabilities/doctor/types.ts +1 -1
- package/src/capabilities/emptyRecovery.test.ts +32 -15
- package/src/capabilities/graph/inspect.verb.ts +3 -2
- package/src/capabilities/graph/query.verb.ts +3 -2
- package/src/capabilities/graph/runQuery.ts +8 -5
- package/src/capabilities/index.ts +22 -18
- package/src/capabilities/info/collectInfo.ts +10 -6
- package/src/capabilities/info/info.render.ts +3 -2
- package/src/capabilities/info/info.verb.ts +3 -2
- package/src/capabilities/lazy.test.ts +93 -2
- package/src/capabilities/ontology/verbs.ts +21 -21
- package/src/capabilities/prompt/prompt.test.ts +12 -6
- package/src/capabilities/prompt/verbs.ts +24 -11
- package/src/capabilities/resources/provider.ts +30 -11
- package/src/capabilities/resources/resources.test.ts +85 -29
- package/src/capabilities/setup/operations/setupGenerator.ts +16 -9
- package/src/capabilities/setup/operations/setupMcp.ts +2 -2
- package/src/capabilities/setup/operations/setupSkills.ts +3 -3
- package/src/capabilities/setup/setup.verb.ts +12 -5
- package/src/capabilities/setup/shell.ts +29 -3
- package/src/capabilities/skill/discover.ts +11 -5
- package/src/capabilities/skill/render.ts +4 -5
- package/src/capabilities/skill/verbs.ts +7 -7
- package/src/capabilities/sources/collectStatus.ts +55 -50
- package/src/capabilities/sources/index.ts +1 -1
- package/src/capabilities/sources/installSkills.ts +2 -2
- package/src/capabilities/sources/runUpdate.ts +113 -122
- package/src/capabilities/sources/sources.test.ts +111 -117
- package/src/capabilities/sources/status.render.test.ts +53 -24
- package/src/capabilities/sources/status.render.ts +24 -29
- package/src/capabilities/sources/status.verb.ts +15 -8
- package/src/capabilities/sources/types.ts +18 -25
- package/src/capabilities/sources/update.render.ts +9 -2
- package/src/capabilities/sources/update.verb.ts +12 -23
- package/src/capabilities/surface.test.ts +33 -10
- package/src/capabilities/tier.parity.test.ts +144 -0
- package/src/capabilities/upgrade/upgrade.verb.ts +7 -3
- package/src/constants.test.ts +8 -6
- package/src/constants.ts +47 -21
- package/src/identity.test.ts +333 -0
- package/src/index.ts +2 -2
- package/src/kernel/completion/__snapshots__/emitScripts.test.ts.snap +5 -2
- package/src/kernel/completion/emitScripts.test.ts +1 -1
- package/src/kernel/completion/emitScripts.ts +4 -2
- package/src/kernel/completion/entitySource.test.ts +185 -41
- package/src/kernel/completion/entitySource.ts +117 -107
- package/src/kernel/completion/model.test.ts +1 -1
- package/src/kernel/completion/model.ts +11 -0
- package/src/kernel/completion/safety.test.ts +82 -36
- package/src/kernel/completion/shellDrive.test.ts +592 -0
- package/src/kernel/completion/templates/fish.ts +28 -6
- package/src/kernel/completion/types.ts +3 -3
- package/src/kernel/config/__snapshots__/firstRun.test.ts.snap +1 -1
- package/src/kernel/config/defaults.test.ts +85 -0
- package/src/kernel/config/defaults.ts +12 -23
- package/src/kernel/config/evaluateProjectConfig.ts +2 -3
- package/src/kernel/config/findProjectConfig.ts +4 -3
- package/src/kernel/config/firstRun.ts +12 -5
- package/src/kernel/config/globalConfig.ts +2 -2
- package/src/kernel/config/index.ts +4 -5
- package/src/kernel/config/paths.ts +17 -17
- package/src/kernel/config/readConfig.test.ts +242 -6
- package/src/kernel/config/readConfig.ts +8 -8
- package/src/kernel/config/schema.test.ts +50 -0
- package/src/kernel/config/schema.ts +97 -10
- package/src/kernel/config/types.ts +73 -19
- package/src/kernel/copy.test.ts +453 -0
- package/src/kernel/error/PragmaError.test.ts +1 -1
- package/src/kernel/error/constants.ts +3 -2
- package/src/kernel/error/index.ts +1 -1
- package/src/kernel/error/recovery.test.ts +22 -45
- package/src/kernel/error/recovery.ts +22 -27
- package/src/kernel/error/types.ts +5 -4
- package/src/kernel/packs/collect.test.ts +195 -11
- package/src/kernel/packs/collect.ts +213 -58
- package/src/kernel/packs/compile.test.ts +163 -7
- package/src/kernel/packs/compile.ts +15 -12
- package/src/kernel/packs/disclosure.test.ts +5 -2
- package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +11 -10
- package/src/kernel/packs/graphqlSource.test.ts +6 -3
- package/src/kernel/packs/iri.ts +5 -7
- package/src/kernel/packs/renderPack.ts +5 -3
- package/src/kernel/packs/resolveEntity.ts +21 -17
- package/src/kernel/packs/runBodies.ts +15 -14
- package/src/kernel/packs/schema.ts +96 -10
- package/src/kernel/packs/sparql/runSelect.test.ts +104 -10
- package/src/kernel/packs/sparql/runSelect.ts +73 -34
- package/src/kernel/packs/toolDescription.test.ts +10 -2
- package/src/kernel/packs/types.ts +39 -4
- package/src/kernel/packs/uniqueness.ts +4 -4
- package/src/kernel/project/cli/buildProgram.test.ts +9 -4
- package/src/kernel/project/cli/dispatch.test.ts +67 -0
- package/src/kernel/project/cli/dispatch.ts +34 -12
- package/src/kernel/project/cli/helpFormat.ts +1 -1
- package/src/kernel/project/cli/rootHelp.ts +105 -105
- package/src/kernel/project/mcp/buildServer.ts +11 -6
- package/src/kernel/project/mcp/instructions.ts +11 -6
- package/src/kernel/project/mcp/parity.test.ts +39 -1
- package/src/kernel/project/mcp/prompts/prompts.test.ts +120 -5
- package/src/kernel/project/mcp/prompts/provider.ts +22 -8
- package/src/kernel/project/mcp/prompts/source.ts +68 -67
- package/src/kernel/project/mcp/registerVerb.ts +25 -6
- package/src/kernel/project/mcp/serve.ts +11 -3
- package/src/kernel/project/mcp/toolDescriptions.test.ts +6 -2
- package/src/kernel/render/disclosure.ts +4 -2
- package/src/kernel/render/prefixes.test.ts +36 -0
- package/src/kernel/render/prefixes.ts +40 -13
- package/src/kernel/render/renderers.test.ts +1 -1
- package/src/kernel/runtime/graphpack/build.ts +29 -3
- package/src/kernel/runtime/graphpack/buildIndex.test.ts +46 -0
- package/src/kernel/runtime/graphpack/buildIndex.ts +52 -17
- package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +5 -5
- package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +3 -3
- package/src/kernel/runtime/graphpack/embedded/pack.stories.generated.ts +3 -0
- package/src/kernel/runtime/graphpack/embedded.ts +37 -11
- package/src/kernel/runtime/graphpack/graphpack.test.ts +205 -5
- package/src/kernel/runtime/graphpack/hash.ts +3 -2
- package/src/kernel/runtime/graphpack/index.ts +1 -1
- package/src/kernel/runtime/graphpack/manifest.ts +114 -12
- package/src/kernel/runtime/graphpack/read.ts +4 -9
- package/src/kernel/runtime/graphpack/schemas.ts +74 -0
- package/src/kernel/runtime/graphpack/stories.ts +84 -0
- package/src/kernel/runtime/graphpack/types.ts +61 -48
- package/src/kernel/runtime/paths.ts +64 -15
- package/src/kernel/runtime/probe.test.ts +8 -4
- package/src/kernel/runtime/readEntity.ts +6 -5
- package/src/kernel/runtime/refs/gitOps.ts +1 -19
- package/src/kernel/runtime/refs/parseRef.ts +7 -7
- package/src/kernel/runtime/refs/resolve.ts +78 -62
- package/src/kernel/runtime/resolveSources.test.ts +63 -24
- package/src/kernel/runtime/resolveSources.ts +36 -25
- package/src/kernel/runtime/storeReadiness.ts +9 -8
- package/src/kernel/runtime/storeless.test.ts +1 -1
- package/src/kernel/runtime/wasmEmbed.test.ts +22 -19
- package/src/kernel/spec/emitReference.test.ts +3 -3
- package/src/kernel/spec/emitReference.ts +144 -11
- package/src/kernel/spec/emitSurface.ts +9 -5
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/surfaceConformance.ts +8 -0
- package/src/kernel/spec/types.ts +29 -9
- package/src/kernel/spec/validate.ts +2 -1
- package/src/kernel/vocabulary.test.ts +164 -0
- package/src/kernel/vocabulary.ts +146 -0
- package/src/testing/PARITY_GAPS.ts +8 -2
- package/src/testing/behavioral/README.md +3 -3
- package/src/testing/behavioral/completion.test.ts +19 -6
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +4 -3
- package/src/testing/behavioral/errorMatrix.storeless.test.ts +1 -1
- package/src/testing/behavioral/exitCodes.e2e.test.ts +6 -5
- package/src/testing/behavioral/harness.foundation.test.ts +14 -5
- package/src/testing/behavioral/journeys.cli.test.ts +116 -75
- package/src/testing/behavioral/journeys.defaultPack.test.ts +82 -176
- package/src/testing/behavioral/journeys.firstInstall.test.ts +167 -0
- package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +9 -6
- package/src/testing/behavioral/journeys.packageStories.test.ts +188 -0
- package/src/testing/behavioral/liveReadSurface.ts +4 -3
- package/src/testing/behavioral/mcpSurface.test.ts +9 -4
- package/src/testing/behavioral/staleCommands.test.ts +10 -0
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +7 -7
- package/src/testing/eval/cases/assembly.ts +13 -6
- package/src/testing/eval/cases/effectful.ts +25 -13
- package/src/testing/eval/cases/readNouns.ts +22 -20
- package/src/testing/eval/cases/stable.ts +5 -1
- package/src/testing/eval/eval.test.ts +7 -1
- package/src/testing/fixtures/fixtureCapability.ts +45 -1
- package/src/testing/fixtures/graph/canonical.ts +6 -3
- package/src/testing/fixtures/graph/defaultPack.ts +6 -5
- package/src/testing/fixtures/graph/owlExport.ts +7 -5
- package/src/testing/helpers/fixtureGraph.ts +33 -16
- package/src/testing/helpers/packRuntime.ts +2 -3
- package/src/testing/helpers/projectCli.ts +2 -1
- package/src/testing/helpers/projectMcp.ts +6 -0
- package/src/testing/perf/budgets.test.ts +4 -0
- package/src/testing/perf/budgets.ts +22 -7
- package/src/testing/perf/globalSetup.ts +121 -6
- package/src/types.ts +2 -2
- package/src/capabilities/block/blockList.test.ts +0 -79
- package/src/capabilities/block/blockList.verb.ts +0 -163
- package/src/capabilities/block/index.ts +0 -25
- package/src/capabilities/block/pack.ts +0 -166
- package/src/capabilities/block/parity.test.ts +0 -187
- package/src/capabilities/block/tierChain.ts +0 -78
- package/src/capabilities/colophon/pragmaColophon.ts +0 -66
- package/src/capabilities/modifier/index.ts +0 -15
- package/src/capabilities/modifier/pack.ts +0 -64
- package/src/capabilities/standard/index.ts +0 -18
- package/src/capabilities/standard/pack.ts +0 -128
- package/src/capabilities/tier/index.ts +0 -19
- package/src/capabilities/tier/lookup.render.test.ts +0 -72
- package/src/capabilities/tier/lookup.render.ts +0 -59
- package/src/capabilities/tier/lookup.test.ts +0 -83
- package/src/capabilities/tier/lookup.verb.ts +0 -44
- package/src/capabilities/tier/pack.ts +0 -28
- package/src/capabilities/tier/runLookup.ts +0 -87
- package/src/capabilities/token/addConfig.render.ts +0 -27
- package/src/capabilities/token/addConfig.test.ts +0 -62
- package/src/capabilities/token/addConfig.verb.ts +0 -40
- package/src/capabilities/token/index.ts +0 -19
- package/src/capabilities/token/pack.ts +0 -58
- package/src/capabilities/token/runAddConfig.ts +0 -95
- package/src/kernel/completion/bashDrive.test.ts +0 -73
- package/src/kernel/runtime/graphpack/embedded/sample.ttl +0 -39
- package/src/kernel/runtime/lock.ts +0 -90
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The published configuration reference agrees with the validator a config
|
|
3
|
+
* actually hits.
|
|
4
|
+
*
|
|
5
|
+
* Two independently produced artifacts: `docs/reference/config.md` is rendered
|
|
6
|
+
* from an exhaustive `Record<keyof RawConfig, …>` (so `tsc` pins its row set to
|
|
7
|
+
* the TYPE), while `rawConfigSchema` is hand-written zod. `parseRawConfig`
|
|
8
|
+
* casts its result `as RawConfig`, so nothing else compares the two — a field
|
|
9
|
+
* the type declares and zod strips, or one zod accepts and the page never
|
|
10
|
+
* mentions, would be invisible.
|
|
11
|
+
*
|
|
12
|
+
* The page is parsed exactly as a reader would read it: the `Field` column of
|
|
13
|
+
* its `## Fields` table. Zod lives here already, so no new import crosses a
|
|
14
|
+
* boundary.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { describe, expect, it } from "vitest";
|
|
18
|
+
import { emitReference } from "../spec/emitReference.js";
|
|
19
|
+
import { rawConfigSchema } from "./schema.js";
|
|
20
|
+
|
|
21
|
+
/** The `field` cells of the generated page's Fields table, in page order. */
|
|
22
|
+
function readDocumentedFields(): string[] {
|
|
23
|
+
const page = emitReference([]).get("config.md") ?? "";
|
|
24
|
+
return [...page.matchAll(/^\| `([a-zA-Z]+)` \| /gm)].map((row) => row.at(1));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("the configuration reference agrees with the validator", () => {
|
|
28
|
+
it("documents exactly the fields the validator accepts", () => {
|
|
29
|
+
expect(readDocumentedFields().sort()).toEqual(
|
|
30
|
+
Object.keys(rawConfigSchema.shape).sort(),
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("marks a field optional iff the validator lets a layer omit it", () => {
|
|
35
|
+
// Every layer field is optional — a layer declares only what it overrides,
|
|
36
|
+
// which is what makes per-field provenance possible. Stated as a derived
|
|
37
|
+
// correspondence rather than a constant so a required field added later
|
|
38
|
+
// fails here instead of quietly contradicting the page.
|
|
39
|
+
const page = emitReference([]).get("config.md") ?? "";
|
|
40
|
+
for (const [field, schema] of Object.entries(rawConfigSchema.shape)) {
|
|
41
|
+
const row = page
|
|
42
|
+
.split("\n")
|
|
43
|
+
.find((line) => line.startsWith(`| \`${field}\` |`));
|
|
44
|
+
expect(row, `no row for \`${field}\``).toBeDefined();
|
|
45
|
+
expect(row?.includes("(optional)"), `\`${field}\` optionality`).toBe(
|
|
46
|
+
schema.safeParse(undefined).success,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -6,32 +6,79 @@
|
|
|
6
6
|
* path, which are storeless and config-free. Validates the raw shape a global
|
|
7
7
|
* JSON file or an evaluated `pragma.config.ts` declares; unknown keys are
|
|
8
8
|
* stripped for forward compatibility, and only present keys survive so layer
|
|
9
|
-
* merging keeps honest per-field provenance.
|
|
9
|
+
* merging keeps honest per-field provenance. Legacy shapes are NOT left to the
|
|
10
|
+
* unknown-key stripping: each is detected before validation and rejected with
|
|
11
|
+
* a loud CONFIG_ERROR naming the file and the fix, so an old config fails
|
|
12
|
+
* telling the user exactly what to change instead of silently ignoring the
|
|
13
|
+
* field. Three today: the `packages` key (renamed to `packs`), and the removed
|
|
14
|
+
* `completion.caseSensitive` and `generators` fields (each validated and read
|
|
15
|
+
* by nothing).
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
18
|
import { z } from "zod";
|
|
13
19
|
import { PragmaError } from "../error/PragmaError.js";
|
|
14
|
-
import { CHANNELS, type RawConfig } from "./types.js";
|
|
20
|
+
import { CHANNELS, DETAIL_LEVELS, type RawConfig } from "./types.js";
|
|
15
21
|
|
|
16
|
-
const
|
|
22
|
+
const packDeclarationSchema = z.union([
|
|
17
23
|
z.string().min(1),
|
|
18
|
-
z.object({
|
|
24
|
+
z.object({
|
|
25
|
+
name: z.string().min(1),
|
|
26
|
+
source: z.string().optional(),
|
|
27
|
+
// Opaque here: the pack grammar is validated by `parsePackDefinition` at
|
|
28
|
+
// dispatch, not by the config layer. Without this key the object arm would
|
|
29
|
+
// STRIP declared stories silently (unknown keys are dropped for forward
|
|
30
|
+
// compatibility), so a pack's stories would vanish with no error.
|
|
31
|
+
stories: z.array(z.unknown()).optional(),
|
|
32
|
+
}),
|
|
19
33
|
]);
|
|
20
34
|
|
|
21
35
|
const completionSchema = z.object({
|
|
22
36
|
minChars: z.number().int().min(0).optional(),
|
|
23
|
-
caseSensitive: z.boolean().optional(),
|
|
24
37
|
families: z.record(z.string(), z.boolean()).optional(),
|
|
25
38
|
});
|
|
26
39
|
|
|
27
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The `completion` object a raw layer declares, when it declares one — read
|
|
42
|
+
* WITHOUT validation, for the removed-field detection that must run before
|
|
43
|
+
* the schema's unknown-key stripping could hide the key.
|
|
44
|
+
*/
|
|
45
|
+
function declaredCompletion(value: unknown): Record<string, unknown> | null {
|
|
46
|
+
if (typeof value !== "object" || value === null) return null;
|
|
47
|
+
const { completion } = value as { completion?: unknown };
|
|
48
|
+
return typeof completion === "object" && completion !== null
|
|
49
|
+
? (completion as Record<string, unknown>)
|
|
50
|
+
: null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The validator every config layer passes through. EXPORTED for
|
|
55
|
+
* `schema.test.ts`, which compares its field set and each field's optionality
|
|
56
|
+
* against the generated `docs/reference/config.md` — the two are produced
|
|
57
|
+
* independently (the page from `keyof RawConfig`, this from hand-written zod)
|
|
58
|
+
* and `parseRawConfig`'s `as RawConfig` cast means `tsc` cannot catch them
|
|
59
|
+
* drifting apart.
|
|
60
|
+
*/
|
|
61
|
+
export const rawConfigSchema = z.object({
|
|
62
|
+
name: z.string().min(1).optional(),
|
|
63
|
+
help: z.string().min(1).optional(),
|
|
64
|
+
// Declared toolchain content: the `colophon` verb renders whatever the
|
|
65
|
+
// distribution declares here (markdown body + optional condensed summary).
|
|
66
|
+
colophon: z
|
|
67
|
+
.object({
|
|
68
|
+
markdown: z.string().min(1),
|
|
69
|
+
summary: z.string().min(1).optional(),
|
|
70
|
+
})
|
|
71
|
+
.optional(),
|
|
72
|
+
issuesUrl: z.string().url().optional(),
|
|
28
73
|
tier: z.string().optional(),
|
|
29
74
|
channel: z.enum(CHANNELS).optional(),
|
|
30
|
-
|
|
31
|
-
|
|
75
|
+
// Closed over the documented ladder, like `channel`: a level the renderer
|
|
76
|
+
// would silently degrade to `standard` is a config error naming the file and
|
|
77
|
+
// the three valid values, not a value `config show` reports as honoured.
|
|
78
|
+
detail: z.enum(DETAIL_LEVELS).optional(),
|
|
79
|
+
packs: z.array(packDeclarationSchema).optional(),
|
|
32
80
|
stories: z.array(z.unknown()).optional(),
|
|
33
81
|
prefixes: z.record(z.string(), z.string()).optional(),
|
|
34
|
-
prompts: z.record(z.string(), z.unknown()).optional(),
|
|
35
82
|
completion: completionSchema.optional(),
|
|
36
83
|
});
|
|
37
84
|
|
|
@@ -41,9 +88,49 @@ const rawConfigSchema = z.object({
|
|
|
41
88
|
* @param value - The parsed JSON or evaluated module default.
|
|
42
89
|
* @param source - The file path, used in error messages.
|
|
43
90
|
* @returns The validated layer values (only the keys actually present).
|
|
44
|
-
* @throws PragmaError with code `CONFIG_ERROR` on an invalid shape
|
|
91
|
+
* @throws PragmaError with code `CONFIG_ERROR` on an invalid shape, when the
|
|
92
|
+
* value declares the legacy `packages` key (renamed to `packs`), or when it
|
|
93
|
+
* still sets the removed `generators` or `completion.caseSensitive` fields.
|
|
45
94
|
*/
|
|
46
95
|
export function parseRawConfig(value: unknown, source: string): RawConfig {
|
|
96
|
+
// Rename detection must precede validation: unknown keys are stripped, so a
|
|
97
|
+
// legacy `packages` field would otherwise vanish silently.
|
|
98
|
+
if (typeof value === "object" && value !== null && "packages" in value) {
|
|
99
|
+
throw PragmaError.configError(
|
|
100
|
+
`Invalid config in ${source}: the "packages" field was renamed to "packs". The entry shape is unchanged.`,
|
|
101
|
+
{
|
|
102
|
+
recovery: {
|
|
103
|
+
message: `In ${source}, rename "packages:" to "packs".`,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
// Removed-field detection, before validation for the same reason: each field
|
|
109
|
+
// was accepted and read by NOTHING, so a config still setting one gets a
|
|
110
|
+
// loud error naming the removed field, not silence. `generators` was ruled
|
|
111
|
+
// dead (L-OPEN-1): `resolveSources` never read it and the `create` verbs
|
|
112
|
+
// resolve their generators statically — declaring it only changed what
|
|
113
|
+
// `config show` printed.
|
|
114
|
+
if (typeof value === "object" && value !== null && "generators" in value) {
|
|
115
|
+
throw PragmaError.configError(
|
|
116
|
+
`Invalid config in ${source}: the "generators" field was removed — it was read by nothing. The create verbs resolve their generators statically.`,
|
|
117
|
+
{
|
|
118
|
+
recovery: {
|
|
119
|
+
message: `In ${source}, delete the "generators" field.`,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if ("caseSensitive" in (declaredCompletion(value) ?? {})) {
|
|
125
|
+
throw PragmaError.configError(
|
|
126
|
+
`Invalid config in ${source}: the "completion.caseSensitive" field was removed — it was read by nothing. Completion matching is declared by the grammar, not configured.`,
|
|
127
|
+
{
|
|
128
|
+
recovery: {
|
|
129
|
+
message: `In ${source}, delete "caseSensitive" from "completion".`,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
}
|
|
47
134
|
const result = rawConfigSchema.safeParse(value ?? {});
|
|
48
135
|
if (!result.success) {
|
|
49
136
|
const issue = result.error.issues[0];
|
|
@@ -13,14 +13,47 @@ export const CHANNELS = ["normal", "experimental", "prerelease"] as const;
|
|
|
13
13
|
/** A release channel name. */
|
|
14
14
|
export type Channel = (typeof CHANNELS)[number];
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Progressive-disclosure levels, least to most detail. Declared HERE, beside
|
|
18
|
+
* {@link CHANNELS}, because the config validator closes `detail` over this set
|
|
19
|
+
* and this module is the one config module the storeless fast path may reach
|
|
20
|
+
* (`completion/safety.test.ts` positive-lists it; `capabilities/lazy.test.ts`
|
|
21
|
+
* pins it inert). `src/constants.ts` re-exports it for every other reader.
|
|
22
|
+
*/
|
|
23
|
+
export const DETAIL_LEVELS = ["summary", "standard", "detailed"] as const;
|
|
24
|
+
|
|
25
|
+
/** A progressive-disclosure level. */
|
|
26
|
+
export type DetailLevel = (typeof DETAIL_LEVELS)[number];
|
|
27
|
+
|
|
28
|
+
/** The object form of a pack source declaration. */
|
|
29
|
+
export interface PackSource {
|
|
18
30
|
readonly name: string;
|
|
19
31
|
readonly source?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Declarative read stories this pack supplies, in the pack grammar
|
|
34
|
+
* (`kernel/packs/types.PackDefinition`). OPAQUE here on purpose — the config
|
|
35
|
+
* layer does not know that grammar; `parsePackDefinition` validates it at
|
|
36
|
+
* dispatch. Declared beside the pack so a story can move out to the package's
|
|
37
|
+
* own `stories/*.json` by deleting this field and nothing else.
|
|
38
|
+
*/
|
|
39
|
+
readonly stories?: readonly unknown[];
|
|
20
40
|
}
|
|
21
41
|
|
|
22
|
-
/** A `
|
|
23
|
-
export type
|
|
42
|
+
/** A `packs` entry: a bare npm name or a `{ name, source }` declaration. */
|
|
43
|
+
export type PackDeclaration = string | PackSource;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The toolchain colophon the distribution declares — CONTENT, not machinery.
|
|
47
|
+
* The `colophon` verb renders whatever is declared here as its first section,
|
|
48
|
+
* titled with the distribution's name; a fork tells its own story by editing
|
|
49
|
+
* its config. Both strings are Markdown BODIES with no leading H1 (the
|
|
50
|
+
* renderer supplies the heading). `summary` is the condensed `--format llm`
|
|
51
|
+
* form; omitted, the full `markdown` serves both.
|
|
52
|
+
*/
|
|
53
|
+
export interface ColophonDeclaration {
|
|
54
|
+
readonly markdown: string;
|
|
55
|
+
readonly summary?: string;
|
|
56
|
+
}
|
|
24
57
|
|
|
25
58
|
/**
|
|
26
59
|
* Completion policy, read at `setup completions` emit time (never on the
|
|
@@ -31,28 +64,41 @@ export type PackageEntry = string | PackageDeclaration;
|
|
|
31
64
|
export interface CompletionConfig {
|
|
32
65
|
/** Minimum typed chars before the shell execs `__complete` (default 2). */
|
|
33
66
|
readonly minChars?: number;
|
|
34
|
-
/** Match case-sensitively (default false — loose match, canonical emit). */
|
|
35
|
-
readonly caseSensitive?: boolean;
|
|
36
67
|
/** Per-family opt-out: a noun mapped to `false` drops its name completion. */
|
|
37
68
|
readonly families?: Readonly<Record<string, boolean>>;
|
|
38
69
|
}
|
|
39
70
|
|
|
40
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* The effective, resolved configuration. `channel` always has a value.
|
|
73
|
+
*
|
|
74
|
+
* IDENTITY IS NOT HERE. `name`, `help` and `issuesUrl` are read from
|
|
75
|
+
* `pragma.conf.ts` by `src/constants.ts` at module load, because the surfaces
|
|
76
|
+
* that need them — `--help`, `__complete`, the MCP handshake, first-run
|
|
77
|
+
* onboarding — all run before or without the config layer; `colophon` is read
|
|
78
|
+
* from the same file at render time by the `colophon` verb. They stay in
|
|
79
|
+
* {@link RawConfig} (the distribution config is `satisfies RawConfig`), but
|
|
80
|
+
* merging them into the effective config only bought `config show` a
|
|
81
|
+
* `[project]` marker the kernel does not honour.
|
|
82
|
+
*/
|
|
41
83
|
export interface PragmaConfig {
|
|
42
84
|
/** Active tier path, or absent when no tier is configured. */
|
|
43
85
|
readonly tier?: string;
|
|
44
86
|
/** Release channel controlling component visibility. */
|
|
45
87
|
readonly channel: Channel;
|
|
46
88
|
/** Default progressive-disclosure level. */
|
|
47
|
-
readonly detail?:
|
|
48
|
-
/** Semantic
|
|
49
|
-
readonly
|
|
50
|
-
/** Declarative read stories compiled at
|
|
89
|
+
readonly detail?: DetailLevel;
|
|
90
|
+
/** Semantic pack sources; replaces (does not merge) across layers. */
|
|
91
|
+
readonly packs?: readonly PackDeclaration[];
|
|
92
|
+
/** Declarative read stories, compiled at DISPATCH (opaque here). */
|
|
51
93
|
readonly stories?: readonly unknown[];
|
|
52
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Namespace prefixes the pack is built with — they win every harvest, so a
|
|
96
|
+
* layer here decides what the store binds and what the index is keyed under.
|
|
97
|
+
* The DISTRIBUTION layer's entries additionally seed the compiled-in
|
|
98
|
+
* `DEFAULT_PREFIX_MAP`; a project layer's do not, because that map is read on
|
|
99
|
+
* the storeless fast path where no config layer exists.
|
|
100
|
+
*/
|
|
53
101
|
readonly prefixes?: Readonly<Record<string, string>>;
|
|
54
|
-
/** Named prompt overrides (global machine state). */
|
|
55
|
-
readonly prompts?: Readonly<Record<string, unknown>>;
|
|
56
102
|
/** Completion policy (read at `setup completions` emit time). */
|
|
57
103
|
readonly completion?: CompletionConfig;
|
|
58
104
|
}
|
|
@@ -61,15 +107,24 @@ export interface PragmaConfig {
|
|
|
61
107
|
* The fields a single config layer (global JSON or project TS) may declare. A
|
|
62
108
|
* key is present only when that layer sets it — presence drives which layer
|
|
63
109
|
* wins during the merge.
|
|
110
|
+
*
|
|
111
|
+
* WIDER than {@link PragmaConfig}: the DISTRIBUTION layer (`pragma.conf.ts`)
|
|
112
|
+
* is `satisfies RawConfig` and declares the four identity fields, which are
|
|
113
|
+
* read statically and never merged. A global or project layer declaring one is
|
|
114
|
+
* accepted by the validator and has no effect — `docs/reference/config.md`
|
|
115
|
+
* says so, and `readConfig.test.ts` pins it.
|
|
64
116
|
*/
|
|
65
117
|
export interface RawConfig {
|
|
118
|
+
readonly name?: string;
|
|
119
|
+
readonly help?: string;
|
|
120
|
+
readonly colophon?: ColophonDeclaration;
|
|
121
|
+
readonly issuesUrl?: string;
|
|
66
122
|
readonly tier?: string;
|
|
67
123
|
readonly channel?: Channel;
|
|
68
|
-
readonly detail?:
|
|
69
|
-
readonly
|
|
124
|
+
readonly detail?: DetailLevel;
|
|
125
|
+
readonly packs?: readonly PackDeclaration[];
|
|
70
126
|
readonly stories?: readonly unknown[];
|
|
71
127
|
readonly prefixes?: Readonly<Record<string, string>>;
|
|
72
|
-
readonly prompts?: Readonly<Record<string, unknown>>;
|
|
73
128
|
readonly completion?: CompletionConfig;
|
|
74
129
|
}
|
|
75
130
|
|
|
@@ -81,10 +136,9 @@ export interface ConfigOrigins {
|
|
|
81
136
|
readonly tier: ConfigOrigin;
|
|
82
137
|
readonly channel: ConfigOrigin;
|
|
83
138
|
readonly detail: ConfigOrigin;
|
|
84
|
-
readonly
|
|
139
|
+
readonly packs: ConfigOrigin;
|
|
85
140
|
readonly stories: ConfigOrigin;
|
|
86
141
|
readonly prefixes: ConfigOrigin;
|
|
87
|
-
readonly prompts: ConfigOrigin;
|
|
88
142
|
}
|
|
89
143
|
|
|
90
144
|
/** A resolved config layer's file location and existence. */
|