@canonical/pragma-cli 0.32.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 +72 -0
- package/dist/pragma +0 -0
- package/package.json +19 -15
- package/pragma.conf.ts +664 -0
- package/src/bin.ts +15 -6
- package/src/capabilities/block.parity.test.ts +250 -0
- package/src/capabilities/capabilities/capabilities.render.ts +3 -2
- package/src/capabilities/capabilities/capabilities.test.ts +10 -1
- package/src/capabilities/capabilities/capabilities.verb.ts +32 -14
- package/src/capabilities/capabilities/catalog.ts +20 -8
- package/src/capabilities/capabilities/hints.ts +21 -36
- package/src/capabilities/capabilities/types.ts +2 -0
- package/src/capabilities/colophon/collectColophon.ts +34 -19
- package/src/capabilities/colophon/colophon.render.test.ts +31 -4
- package/src/capabilities/colophon/colophon.render.ts +13 -4
- package/src/capabilities/colophon/colophon.test.ts +3 -3
- package/src/capabilities/colophon/colophon.verb.ts +11 -4
- package/src/capabilities/colophon/markdownTerminal.ts +33 -14
- 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 +10 -108
- package/src/capabilities/config/set.test.ts +6 -6
- package/src/capabilities/config/set.verb.ts +12 -8
- package/src/capabilities/config/show.render.test.ts +137 -0
- package/src/capabilities/config/show.render.ts +57 -16
- package/src/capabilities/config/show.verb.ts +9 -8
- package/src/capabilities/config/types.ts +8 -0
- package/src/capabilities/create/byteEquality.subprocess.test.ts +1 -1
- package/src/capabilities/create/byteEquality.test.ts +82 -101
- package/src/capabilities/create/compiledCreate.subprocess.test.ts +53 -16
- 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 +192 -16
- package/src/capabilities/create/create.verb.ts +208 -79
- 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/checkMcpCommands.ts +6 -0
- package/src/capabilities/doctor/checks/checkMcpConfigured.ts +15 -8
- 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/checks/deriveBand.test.ts +42 -0
- package/src/capabilities/doctor/checks/deriveBand.ts +28 -0
- package/src/capabilities/doctor/doctor.render.test.ts +170 -0
- package/src/capabilities/doctor/doctor.render.ts +117 -34
- package/src/capabilities/doctor/doctor.test.ts +68 -9
- package/src/capabilities/doctor/doctor.verb.ts +6 -2
- package/src/capabilities/doctor/runChecks.ts +33 -9
- package/src/capabilities/doctor/types.ts +16 -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/index.ts +10 -3
- package/src/capabilities/ontology/ontology.test.ts +157 -5
- package/src/capabilities/ontology/verbs.ts +203 -104
- package/src/capabilities/prompt/prompt.render.test.ts +94 -0
- package/src/capabilities/prompt/prompt.render.ts +23 -6
- package/src/capabilities/prompt/prompt.test.ts +68 -1
- package/src/capabilities/prompt/verbs.ts +24 -11
- package/src/capabilities/reference.test.ts +32 -0
- package/src/capabilities/resources/provider.ts +58 -25
- package/src/capabilities/resources/resources.test.ts +176 -21
- package/src/capabilities/scopeTypeSync.test.ts +37 -0
- package/src/capabilities/setup/index.ts +7 -1
- package/src/capabilities/setup/operations/setupCompletions.ts +49 -16
- package/src/capabilities/setup/operations/setupGenerator.ts +166 -63
- package/src/capabilities/setup/operations/setupLsp.ts +56 -12
- package/src/capabilities/setup/operations/setupMcp.ts +216 -39
- package/src/capabilities/setup/operations/setupSkills.ts +10 -4
- package/src/capabilities/setup/setup.render.test.ts +109 -0
- package/src/capabilities/setup/setup.render.ts +61 -14
- package/src/capabilities/setup/setup.test.ts +352 -1
- package/src/capabilities/setup/setup.verb.ts +68 -9
- package/src/capabilities/setup/shell.ts +29 -3
- package/src/capabilities/setup/types.ts +59 -2
- package/src/capabilities/shared/bands.ts +16 -0
- 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 +69 -49
- package/src/capabilities/sources/index.ts +1 -1
- package/src/capabilities/sources/installSkills.ts +2 -2
- package/src/capabilities/sources/runUpdate.ts +146 -98
- package/src/capabilities/sources/sources.test.ts +264 -84
- package/src/capabilities/sources/status.render.test.ts +94 -0
- package/src/capabilities/sources/status.render.ts +55 -33
- 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 +65 -17
- package/src/capabilities/tier.parity.test.ts +144 -0
- package/src/capabilities/upgrade/upgrade.verb.ts +7 -3
- package/src/constants.test.ts +9 -7
- package/src/constants.ts +49 -23
- package/src/identity.test.ts +333 -0
- package/src/index.ts +2 -2
- package/src/kernel/completion/__snapshots__/emitScripts.test.ts.snap +18 -16
- package/src/kernel/completion/complete.test.ts +3 -5
- 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 +131 -113
- package/src/kernel/completion/model.test.ts +3 -3
- package/src/kernel/completion/model.ts +11 -1
- package/src/kernel/completion/parse.test.ts +2 -4
- 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 +5 -5
- 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/renderError.ts +1 -1
- 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 +60 -11
- package/src/kernel/project/cli/buildProgram.ts +11 -0
- package/src/kernel/project/cli/dispatch.test.ts +67 -0
- package/src/kernel/project/cli/dispatch.ts +34 -12
- package/src/kernel/project/cli/globalFlags.test.ts +12 -4
- package/src/kernel/project/cli/globalFlags.ts +14 -14
- package/src/kernel/project/cli/helpFormat.ts +1 -1
- package/src/kernel/project/cli/rootHelp.ts +109 -107
- package/src/kernel/project/mcp/buildServer.ts +11 -6
- package/src/kernel/project/mcp/instructions.ts +12 -7
- package/src/kernel/project/mcp/mcpError.ts +52 -0
- package/src/kernel/project/mcp/parity.test.ts +39 -1
- package/src/kernel/project/mcp/prompts/prompts.test.ts +128 -5
- package/src/kernel/project/mcp/prompts/provider.ts +51 -7
- 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/formatters.ts +5 -4
- package/src/kernel/render/prefixes.test.ts +36 -0
- package/src/kernel/render/prefixes.ts +40 -13
- package/src/kernel/render/renderers.test.ts +35 -1
- package/src/kernel/render/renderers.ts +25 -7
- package/src/kernel/render/style.test.ts +31 -0
- package/src/kernel/render/style.ts +74 -0
- package/src/kernel/runtime/graphpack/build.ts +57 -3
- package/src/kernel/runtime/graphpack/buildIndex.test.ts +149 -0
- package/src/kernel/runtime/graphpack/buildIndex.ts +173 -50
- package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +5 -8
- package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +3 -4
- 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 +274 -6
- 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 +32 -22
- 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 +72 -45
- package/src/kernel/runtime/loadSession.ts +4 -12
- 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 +141 -65
- package/src/kernel/runtime/resolveSources.test.ts +63 -24
- package/src/kernel/runtime/resolveSources.ts +36 -25
- package/src/kernel/runtime/storeReadiness.ts +62 -0
- package/src/kernel/runtime/storeless.test.ts +1 -1
- package/src/kernel/runtime/types.ts +1 -1
- package/src/kernel/runtime/wasmEmbed.test.ts +25 -20
- package/src/kernel/spec/emitReference.test.ts +196 -0
- package/src/kernel/spec/emitReference.ts +624 -0
- package/src/kernel/spec/emitSurface.ts +13 -7
- package/src/kernel/spec/index.ts +2 -0
- 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 +9 -3
- package/src/testing/behavioral/README.md +3 -3
- package/src/testing/behavioral/autoLlm.e2e.test.ts +12 -2
- package/src/testing/behavioral/completion.test.ts +21 -8
- package/src/testing/behavioral/disclosure.test.ts +12 -0
- package/src/testing/behavioral/docExamples.test.ts +283 -0
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +4 -3
- package/src/testing/behavioral/errorMatrix.storeless.test.ts +3 -2
- 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 -73
- package/src/testing/behavioral/journeys.defaultPack.test.ts +477 -0
- package/src/testing/behavioral/journeys.firstInstall.test.ts +167 -0
- package/src/testing/behavioral/journeys.interactiveTty.e2e.test.ts +66 -0
- package/src/testing/behavioral/journeys.livePack.e2e.test.ts +129 -0
- package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +179 -0
- 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 +10 -5
- package/src/testing/behavioral/staleCommands.test.ts +86 -0
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +9 -9
- package/src/testing/eval/cases/assembly.ts +16 -9
- package/src/testing/eval/cases/effectful.ts +31 -16
- package/src/testing/eval/cases/readNouns.ts +23 -18
- package/src/testing/eval/cases/stable.ts +5 -1
- package/src/testing/eval/eval.test.ts +7 -1
- package/src/testing/fixtures/fixtureCapability.ts +201 -1
- package/src/testing/fixtures/graph/canonical.ts +6 -3
- package/src/testing/fixtures/graph/defaultPack.ts +179 -0
- package/src/testing/fixtures/graph/owlExport.ts +97 -0
- package/src/testing/helpers/extractSnippets.ts +29 -0
- package/src/testing/helpers/fixtureGraph.ts +33 -16
- package/src/testing/helpers/golden.ts +1 -1
- 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.verb.ts +0 -150
- package/src/capabilities/block/index.ts +0 -25
- package/src/capabilities/block/pack.ts +0 -155
- package/src/capabilities/block/parity.test.ts +0 -180
- package/src/capabilities/block/tierChain.ts +0 -78
- package/src/capabilities/colophon/pragmaColophon.ts +0 -66
- package/src/capabilities/config/field.test.ts +0 -188
- 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.ts +0 -34
- package/src/capabilities/tier/lookup.test.ts +0 -68
- package/src/capabilities/tier/lookup.verb.ts +0 -44
- package/src/capabilities/tier/pack.ts +0 -28
- package/src/capabilities/tier/runLookup.ts +0 -59
- 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
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `config set <key> <value>` — the
|
|
2
|
+
* `config set <key> <value>` — the one-command config setter (PR9, COVENANT).
|
|
3
3
|
*
|
|
4
4
|
* Pins the emitted covenant slice (`{ v:"set", args:["<key>","<value>"],
|
|
5
|
-
* mutates:true, mcp:"config_set" }`), proves it
|
|
6
|
-
* (set / reset-sentinel / enum-backstop), rejects an unknown key and
|
|
7
|
-
* out-of-set enum value with INVALID_INPUT, and holds MCP plan-first/confirm
|
|
8
|
-
* parity.
|
|
9
|
-
*
|
|
5
|
+
* mutates:true, mcp:"config_set" }`), proves it drives the shared per-field
|
|
6
|
+
* write path (set / reset-sentinel / enum-backstop), rejects an unknown key and
|
|
7
|
+
* an out-of-set enum value with INVALID_INPUT, and holds MCP plan-first/confirm
|
|
8
|
+
* parity. Since AV-228 B3 retired `config tier/channel/detail`, `config set` is
|
|
9
|
+
* the sole config setter — `config set <field> <value>` is the migration path.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `config set <key> <value>` — the one-command config setter (ADDITIVE).
|
|
3
3
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The single form for writing config: `pragma config set tier apps/lxd`. Since
|
|
5
|
+
* AV-228 B3 retired the per-field `config tier`/`channel`/`detail` verbs, this
|
|
6
|
+
* is now the ONLY config setter. It drives the shared write path (`runField` via
|
|
7
|
+
* `runSet`), so it inherits reset sentinels, enum re-validation, and the
|
|
8
|
+
* global-layer-only write from the {@link CONFIG_FIELDS} table.
|
|
9
9
|
*
|
|
10
10
|
* Covenant shape: `<key>` is an ENUM over the field names (better completion +
|
|
11
11
|
* validation; the token still emits as `<key>`), `<value>` a free string, so
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { Task } from "@canonical/task";
|
|
17
|
+
import { BIN_NAME } from "../../constants.js";
|
|
17
18
|
import { asVerb } from "../../kernel/spec/asVerb.js";
|
|
18
19
|
import type { VerbSpec } from "../../kernel/spec/types.js";
|
|
19
20
|
import { configFieldFormatters } from "./field.render.js";
|
|
@@ -46,9 +47,12 @@ const setVerb: VerbSpec<Record<string, unknown>, ConfigFieldResult> = {
|
|
|
46
47
|
],
|
|
47
48
|
output: { formatters: configFieldFormatters },
|
|
48
49
|
examples: [
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
{
|
|
51
|
+
cmd: `${BIN_NAME} config set tier apps/lxd`,
|
|
52
|
+
note: "scope reads to a tier",
|
|
53
|
+
},
|
|
54
|
+
{ cmd: `${BIN_NAME} config set channel experimental` },
|
|
55
|
+
{ cmd: `${BIN_NAME} config set tier none`, note: "clear the tier" },
|
|
52
56
|
],
|
|
53
57
|
capability: {
|
|
54
58
|
needsStore: false,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { type RenderStyle, styleFor } from "../../kernel/render/style.js";
|
|
3
|
+
import { emitReference } from "../../kernel/spec/emitReference.js";
|
|
4
|
+
import { capabilities } from "../index.js";
|
|
5
|
+
import { configShowFormatters, renderConfigShowPlain } from "./show.render.js";
|
|
6
|
+
import type { ConfigShowData } from "./types.js";
|
|
7
|
+
|
|
8
|
+
const DATA: ConfigShowData = {
|
|
9
|
+
config: {
|
|
10
|
+
tier: "apps/lxd",
|
|
11
|
+
channel: "normal",
|
|
12
|
+
detail: "standard",
|
|
13
|
+
packs: ["@canonical/ds"],
|
|
14
|
+
},
|
|
15
|
+
origins: {
|
|
16
|
+
tier: "project",
|
|
17
|
+
channel: "default",
|
|
18
|
+
detail: "default",
|
|
19
|
+
packs: "global",
|
|
20
|
+
stories: "default",
|
|
21
|
+
prefixes: "default",
|
|
22
|
+
},
|
|
23
|
+
globalConfigPath: "/home/u/.config/pragma/config.json",
|
|
24
|
+
projectConfigPath: "/repo/pragma.config.ts",
|
|
25
|
+
projectExists: true,
|
|
26
|
+
globalExists: true,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** A sentinel styler — enabled, each color wrapped in a visible tag. */
|
|
30
|
+
const TAGGED: RenderStyle = {
|
|
31
|
+
enabled: true,
|
|
32
|
+
bold: (t) => `<b>${t}</b>`,
|
|
33
|
+
dim: (t) => `<d>${t}</d>`,
|
|
34
|
+
cyan: (t) => `<c>${t}</c>`,
|
|
35
|
+
green: (t) => `<g>${t}</g>`,
|
|
36
|
+
yellow: (t) => `<y>${t}</y>`,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
describe("renderConfigShowPlain", () => {
|
|
40
|
+
it("is byte-identical to the plain form when the styler is disabled", () => {
|
|
41
|
+
expect(renderConfigShowPlain(DATA, styleFor(false))).toBe(
|
|
42
|
+
[
|
|
43
|
+
"tier: apps/lxd [project]",
|
|
44
|
+
"channel: normal",
|
|
45
|
+
"detail: standard",
|
|
46
|
+
"packs: @canonical/ds [global]",
|
|
47
|
+
"global config: /home/u/.config/pragma/config.json",
|
|
48
|
+
"project config: /repo/pragma.config.ts",
|
|
49
|
+
].join("\n"),
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("aligns the key column and colorizes values on a TTY", () => {
|
|
54
|
+
const out = renderConfigShowPlain(DATA, TAGGED);
|
|
55
|
+
const keyWidth = "project config:".length;
|
|
56
|
+
// Dim, padded key; cyan value; dim `[layer]` marker.
|
|
57
|
+
expect(out).toContain(
|
|
58
|
+
`<d>${"tier:".padEnd(keyWidth)}</d> <c>apps/lxd</c><d> [project]</d>`,
|
|
59
|
+
);
|
|
60
|
+
// A default-origin value carries no marker.
|
|
61
|
+
expect(out).toContain(
|
|
62
|
+
`<d>${"channel:".padEnd(keyWidth)}</d> <c>normal</c>`,
|
|
63
|
+
);
|
|
64
|
+
expect(out).not.toContain("<d> [default]</d>");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("renders absent optional fields as (none)", () => {
|
|
68
|
+
const bare: ConfigShowData = {
|
|
69
|
+
config: { channel: "normal" },
|
|
70
|
+
origins: {
|
|
71
|
+
tier: "default",
|
|
72
|
+
channel: "default",
|
|
73
|
+
detail: "default",
|
|
74
|
+
packs: "default",
|
|
75
|
+
stories: "default",
|
|
76
|
+
prefixes: "default",
|
|
77
|
+
},
|
|
78
|
+
globalConfigPath: "/home/u/.config/pragma/config.json",
|
|
79
|
+
projectExists: false,
|
|
80
|
+
globalExists: false,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const out = renderConfigShowPlain(bare, styleFor(false));
|
|
84
|
+
|
|
85
|
+
expect(out).toContain("tier: (none)");
|
|
86
|
+
expect(out).toContain("packs: (none)");
|
|
87
|
+
expect(out).toContain("project config: (not found)");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("configShowFormatters.llm", () => {
|
|
92
|
+
it("renders the layered rows with origin markers", () => {
|
|
93
|
+
const out = configShowFormatters.llm(DATA);
|
|
94
|
+
|
|
95
|
+
expect(out).toContain("- **Tier:** apps/lxd [project]");
|
|
96
|
+
expect(out).toContain("- **Packs:** @canonical/ds [global]");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("reports no identity row, in either form", () => {
|
|
100
|
+
// Identity is read statically from `pragma.conf.ts`; reporting a layer for
|
|
101
|
+
// it was reporting a provenance the kernel does not honour. Both renderers
|
|
102
|
+
// are asserted, because they list their rows independently.
|
|
103
|
+
for (const out of [
|
|
104
|
+
renderConfigShowPlain(DATA, styleFor(false)),
|
|
105
|
+
configShowFormatters.llm(DATA),
|
|
106
|
+
]) {
|
|
107
|
+
for (const field of ["name", "help", "colophon", "issues"]) {
|
|
108
|
+
expect(out.toLowerCase()).not.toContain(`${field}:`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("the generated configuration reference", () => {
|
|
115
|
+
it("names exactly the fields this renderer reports with a layer", () => {
|
|
116
|
+
// The page and the renderer are written independently — the page is kernel
|
|
117
|
+
// prose, the renderer a capability — and the page's account of the renderer
|
|
118
|
+
// was wrong in both directions: it claimed every field but `completion`
|
|
119
|
+
// carried a printed provenance, while `prefixes`, `stories` and the four
|
|
120
|
+
// distribution-only fields do not, and it claimed `completion` was not
|
|
121
|
+
// printed, while `--format json` carries it.
|
|
122
|
+
//
|
|
123
|
+
// DERIVED from the real formatter: the field rows are the ones before the
|
|
124
|
+
// two PATH rows, which are not fields at all. Adding a row here without
|
|
125
|
+
// saying so on the page, or naming a field there this renderer drops, fails.
|
|
126
|
+
const printed = renderConfigShowPlain(DATA, styleFor(false))
|
|
127
|
+
.split("\n")
|
|
128
|
+
.map((line) => line.slice(0, line.indexOf(":")));
|
|
129
|
+
const fields = printed.slice(0, printed.indexOf("global config"));
|
|
130
|
+
expect(fields.length).toBeGreaterThan(0);
|
|
131
|
+
|
|
132
|
+
const page = emitReference(capabilities).get("config.md") ?? "";
|
|
133
|
+
expect(page).toContain(
|
|
134
|
+
`${fields.map((field) => `\`${field}\``).join(", ")} — those and only those —`,
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { ConfigOrigin } from "../../kernel/config/types.js";
|
|
10
|
+
import { defaultStyle, type RenderStyle } from "../../kernel/render/style.js";
|
|
10
11
|
import type { Formatters } from "../../kernel/spec/types.js";
|
|
11
12
|
import type { ConfigShowData } from "./types.js";
|
|
12
13
|
|
|
@@ -15,27 +16,67 @@ function originMarker(origin: ConfigOrigin): string {
|
|
|
15
16
|
return origin === "default" ? "" : ` [${origin}]`;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
/** Summarize
|
|
19
|
-
function
|
|
20
|
-
const
|
|
21
|
-
const names = packages.map((entry) =>
|
|
19
|
+
/** Summarize a list of named entries as a comma-separated set of names. */
|
|
20
|
+
function entryNames(entries: readonly (string | { name: string })[]): string {
|
|
21
|
+
const names = entries.map((entry) =>
|
|
22
22
|
typeof entry === "string" ? entry : entry.name,
|
|
23
23
|
);
|
|
24
24
|
return names.length > 0 ? names.join(", ") : "(none)";
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/** One resolved row: its label, value, and `[layer]` marker (blank for a default). */
|
|
28
|
+
type ConfigRow = readonly [label: string, value: string, marker: string];
|
|
29
|
+
|
|
30
|
+
/** The resolved rows, in display order, shared by the plain + beautified forms. */
|
|
31
|
+
function configRows(data: ConfigShowData): readonly ConfigRow[] {
|
|
32
|
+
const { config, origins } = data;
|
|
33
|
+
return [
|
|
34
|
+
["tier", config.tier ?? "(none)", originMarker(origins.tier)],
|
|
35
|
+
["channel", config.channel, originMarker(origins.channel)],
|
|
36
|
+
["detail", config.detail ?? "standard", originMarker(origins.detail)],
|
|
37
|
+
["packs", entryNames(config.packs ?? []), originMarker(origins.packs)],
|
|
38
|
+
[
|
|
39
|
+
"global config",
|
|
40
|
+
`${data.globalConfigPath}${data.globalExists ? "" : " (not found)"}`,
|
|
41
|
+
"",
|
|
42
|
+
],
|
|
43
|
+
["project config", data.projectConfigPath ?? "(not found)", ""],
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Render `config show` as plain text.
|
|
49
|
+
*
|
|
50
|
+
* @param data - The resolved config-show payload.
|
|
51
|
+
* @param style - TTY styling; defaults to the process style. On a color-capable
|
|
52
|
+
* terminal the `key:` column is aligned + dim, values cyan, and `[layer]`
|
|
53
|
+
* markers dim; off a TTY the styler is inert, so the output is byte-identical
|
|
54
|
+
* to the pre-beautify `key: value[marker]` form.
|
|
55
|
+
* @returns The formatted config block.
|
|
56
|
+
*/
|
|
57
|
+
export function renderConfigShowPlain(
|
|
58
|
+
data: ConfigShowData,
|
|
59
|
+
style: RenderStyle = defaultStyle(),
|
|
60
|
+
): string {
|
|
61
|
+
const rows = configRows(data);
|
|
62
|
+
if (!style.enabled) {
|
|
63
|
+
return rows
|
|
64
|
+
.map(([label, value, marker]) => `${label}: ${value}${marker}`)
|
|
65
|
+
.join("\n");
|
|
66
|
+
}
|
|
67
|
+
const keyWidth = Math.max(...rows.map(([label]) => `${label}:`.length));
|
|
68
|
+
return rows
|
|
69
|
+
.map(([label, value, marker]) => {
|
|
70
|
+
const key = style.dim(`${label}:`.padEnd(keyWidth));
|
|
71
|
+
const tail = marker ? style.dim(marker) : "";
|
|
72
|
+
return `${key} ${style.cyan(value)}${tail}`;
|
|
73
|
+
})
|
|
74
|
+
.join("\n");
|
|
75
|
+
}
|
|
76
|
+
|
|
27
77
|
export const configShowFormatters: Formatters<ConfigShowData> = {
|
|
28
78
|
plain(data) {
|
|
29
|
-
|
|
30
|
-
const lines = [
|
|
31
|
-
`tier: ${config.tier ?? "(none — all tiers visible)"}${originMarker(origins.tier)}`,
|
|
32
|
-
`channel: ${config.channel}${originMarker(origins.channel)}`,
|
|
33
|
-
`detail: ${config.detail ?? "standard"}${originMarker(origins.detail)}`,
|
|
34
|
-
`packages: ${packageNames(data)}${originMarker(origins.packages)}`,
|
|
35
|
-
`global config: ${data.globalConfigPath}${data.globalExists ? "" : " (not found)"}`,
|
|
36
|
-
`project config: ${data.projectConfigPath ?? "(not found)"}`,
|
|
37
|
-
];
|
|
38
|
-
return lines.join("\n");
|
|
79
|
+
return renderConfigShowPlain(data);
|
|
39
80
|
},
|
|
40
81
|
|
|
41
82
|
llm(data) {
|
|
@@ -43,10 +84,10 @@ export const configShowFormatters: Formatters<ConfigShowData> = {
|
|
|
43
84
|
const lines = [
|
|
44
85
|
"## Configuration",
|
|
45
86
|
"",
|
|
46
|
-
`- **Tier:** ${config.tier ?? "none
|
|
87
|
+
`- **Tier:** ${config.tier ?? "none"}${originMarker(origins.tier)}`,
|
|
47
88
|
`- **Channel:** ${config.channel}${originMarker(origins.channel)}`,
|
|
48
89
|
`- **Detail:** ${config.detail ?? "standard"}${originMarker(origins.detail)}`,
|
|
49
|
-
`- **
|
|
90
|
+
`- **Packs:** ${entryNames(config.packs ?? [])}${originMarker(origins.packs)}`,
|
|
50
91
|
`- **Global config:** \`${data.globalConfigPath}\``,
|
|
51
92
|
];
|
|
52
93
|
if (data.projectConfigPath) {
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* later PR — this ships only the reader.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { BIN_NAME, PROJECT_CONFIG_FILENAME } from "../../constants.js";
|
|
8
9
|
import { asVerb } from "../../kernel/spec/asVerb.js";
|
|
9
10
|
import type { CapabilityModule, VerbSpec } from "../../kernel/spec/types.js";
|
|
10
|
-
import { configFieldVerbs } from "./fields.js";
|
|
11
11
|
import { configSetVerb } from "./set.verb.js";
|
|
12
12
|
import { configShowFormatters } from "./show.render.js";
|
|
13
13
|
import type { ConfigShowData } from "./types.js";
|
|
@@ -15,12 +15,12 @@ import type { ConfigShowData } from "./types.js";
|
|
|
15
15
|
const showVerb: VerbSpec<Record<string, unknown>, ConfigShowData> = {
|
|
16
16
|
path: ["config", "show"],
|
|
17
17
|
summary: "Show the resolved config and per-field provenance.",
|
|
18
|
-
doc:
|
|
18
|
+
doc: `Merges built-in defaults, the global XDG config, and the nearest ${PROJECT_CONFIG_FILENAME}, marking which layer supplied each value.`,
|
|
19
19
|
params: [],
|
|
20
20
|
output: { formatters: configShowFormatters },
|
|
21
21
|
examples: [
|
|
22
|
-
{ cmd:
|
|
23
|
-
{ cmd:
|
|
22
|
+
{ cmd: `${BIN_NAME} config show` },
|
|
23
|
+
{ cmd: `${BIN_NAME} config show --format json` },
|
|
24
24
|
],
|
|
25
25
|
capability: {
|
|
26
26
|
needsStore: false,
|
|
@@ -35,11 +35,12 @@ const showVerb: VerbSpec<Record<string, unknown>, ConfigShowData> = {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* The `config` capability module: the `show` reader (PR1)
|
|
39
|
-
* `
|
|
40
|
-
*
|
|
38
|
+
* The `config` capability module: the `show` reader (PR1) and the one-command
|
|
39
|
+
* `set <key> <value>` setter (PR9), emitted in covenant order. The per-field
|
|
40
|
+
* `tier`/`channel`/`detail` verbs were retired in favour of `config set`
|
|
41
|
+
* (AV-228 B3).
|
|
41
42
|
*/
|
|
42
43
|
export const configModule: CapabilityModule = {
|
|
43
44
|
name: "config",
|
|
44
|
-
verbs: [asVerb(showVerb),
|
|
45
|
+
verbs: [asVerb(showVerb), configSetVerb],
|
|
45
46
|
};
|
|
@@ -6,6 +6,14 @@ import type { ConfigOrigins, PragmaConfig } from "../../kernel/config/types.js";
|
|
|
6
6
|
|
|
7
7
|
/** The resolved configuration plus per-field provenance and layer locations. */
|
|
8
8
|
export interface ConfigShowData {
|
|
9
|
+
/**
|
|
10
|
+
* The effective config, MINUS declared story bodies: `packs` entries carry
|
|
11
|
+
* `{ name, source }` only and the top-level `stories` array is omitted. The
|
|
12
|
+
* bodies are SPARQL, and MCP returns the JSON formatter's output verbatim, so
|
|
13
|
+
* carrying them would put ~2.7k tokens of query text in every `config_show`
|
|
14
|
+
* call. `origins` still reports where `packs`/`stories` came from, and
|
|
15
|
+
* `pragma capabilities` lists the verbs those stories produce.
|
|
16
|
+
*/
|
|
9
17
|
readonly config: PragmaConfig;
|
|
10
18
|
readonly origins: ConfigOrigins;
|
|
11
19
|
readonly projectConfigPath?: string;
|
|
@@ -20,7 +20,7 @@ import { describe, expect, it } from "vitest";
|
|
|
20
20
|
|
|
21
21
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
22
22
|
const repoRoot = resolve(here, "../../../../../..");
|
|
23
|
-
const pragmaBin = join(repoRoot, "packages/cli/
|
|
23
|
+
const pragmaBin = join(repoRoot, "packages/cli/pragma/src/bin.ts");
|
|
24
24
|
const summonCore = join(repoRoot, "packages/summon/core/dist/esm/index.js");
|
|
25
25
|
const pickGen = join(here, "pickGenerator.ts");
|
|
26
26
|
const freshCwd = (): string => mkdtempSync(join(tmpdir(), "pragma-xbin-"));
|
|
@@ -1,29 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PROTECTED — the
|
|
3
|
-
* ways and diffed byte-for-byte (path set + contents, incl.
|
|
4
|
-
* stamp): (1) `pragma create <verb> --yes` through the kernel
|
|
5
|
-
* (2) summon-core `execute` with `autoPrompt`,
|
|
6
|
-
*
|
|
7
|
-
* StampConfig from `createGeneratorStamp` (displayName + version) and
|
|
8
|
-
* SAME `generator.generate` with the SAME answers.
|
|
2
|
+
* PROTECTED — pragma's side of the byte-equality seam contract: every `create`
|
|
3
|
+
* tree is produced TWO ways and diffed byte-for-byte (path set + contents, incl.
|
|
4
|
+
* the "Generated by" stamp): (1) `pragma create <verb> --yes` through the kernel
|
|
5
|
+
* dispatcher, and (2) the REFERENCE — summon-core `execute` with `autoPrompt`,
|
|
6
|
+
* run through `runGeneratorTask` + the shared stamp. They match because both
|
|
7
|
+
* derive the StampConfig from `createGeneratorStamp` (displayName + version) and
|
|
8
|
+
* run the SAME `generator.generate` with the SAME answers.
|
|
9
|
+
*
|
|
10
|
+
* The reference producer, the tree snapshot/diff, and the answer sets are NOT
|
|
11
|
+
* defined here any more: they are `@canonical/summon-core/testing`, the named
|
|
12
|
+
* conformance suite both bins run (L-OPEN-10). This file supplies what only
|
|
13
|
+
* pragma can — its kernel dispatch path, and the mapping from a fixture's
|
|
14
|
+
* logical generator id to the bundled generator plus the CLI param names the
|
|
15
|
+
* `create` verbs take. No new package edge: pragma already depends on
|
|
16
|
+
* summon-core, and never on the summon bin.
|
|
9
17
|
*
|
|
10
18
|
* Five generators are covered: component × {react, svelte, lit}, package, and
|
|
11
19
|
* application. A cross-binary subprocess guard lives in byteEquality.subprocess.test.ts.
|
|
12
20
|
*/
|
|
13
21
|
|
|
14
|
-
import { mkdtempSync
|
|
22
|
+
import { mkdtempSync } from "node:fs";
|
|
15
23
|
import { tmpdir } from "node:os";
|
|
16
24
|
import { join } from "node:path";
|
|
25
|
+
import {
|
|
26
|
+
CONFORMANCE_FIXTURES,
|
|
27
|
+
diffTrees,
|
|
28
|
+
formatTreeDiff,
|
|
29
|
+
isIdentical,
|
|
30
|
+
produceReference,
|
|
31
|
+
snapshotTree,
|
|
32
|
+
type TreeSnapshot,
|
|
33
|
+
} from "@canonical/summon-core/testing";
|
|
17
34
|
import { describe, expect, it } from "vitest";
|
|
18
35
|
import { executeVerb } from "../../kernel/project/cli/dispatch.js";
|
|
19
36
|
import { bootRuntime } from "../../kernel/runtime/boot.js";
|
|
20
37
|
import type { GlobalFlags } from "../../kernel/runtime/types.js";
|
|
21
38
|
import type { VerbSpec } from "../../kernel/spec/types.js";
|
|
22
|
-
import {
|
|
23
|
-
createApplicationVerb,
|
|
24
|
-
createComponentVerb,
|
|
25
|
-
createPackageVerb,
|
|
26
|
-
} from "./create.verb.js";
|
|
39
|
+
import { createVerbs } from "./create.verb.js";
|
|
27
40
|
import type { CreateKind } from "./types.js";
|
|
28
41
|
|
|
29
42
|
const FLAGS: GlobalFlags = {
|
|
@@ -34,39 +47,17 @@ const FLAGS: GlobalFlags = {
|
|
|
34
47
|
};
|
|
35
48
|
const freshCwd = (): string => mkdtempSync(join(tmpdir(), "pragma-golden-"));
|
|
36
49
|
|
|
37
|
-
/** Read a directory tree into a sorted map of relative path → contents. */
|
|
38
|
-
function snapshot(dir: string): Map<string, string> {
|
|
39
|
-
const out = new Map<string, string>();
|
|
40
|
-
const walk = (d: string, base: string): void => {
|
|
41
|
-
for (const entry of readdirSync(d, { withFileTypes: true }).sort((a, b) =>
|
|
42
|
-
a.name.localeCompare(b.name),
|
|
43
|
-
)) {
|
|
44
|
-
const rel = base ? `${base}/${entry.name}` : entry.name;
|
|
45
|
-
if (entry.isDirectory()) walk(join(d, entry.name), rel);
|
|
46
|
-
else out.set(rel, readFileSync(join(d, entry.name), "utf-8"));
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
walk(dir, "");
|
|
50
|
-
return out;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const verbFor: Record<CreateKind, VerbSpec> = {
|
|
54
|
-
component: createComponentVerb as VerbSpec,
|
|
55
|
-
package: createPackageVerb as VerbSpec,
|
|
56
|
-
application: createApplicationVerb as VerbSpec,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
50
|
/** Producer (1): the full pragma kernel path — dispatcher runs the create verb. */
|
|
60
51
|
async function producePragma(
|
|
61
52
|
kind: CreateKind,
|
|
62
53
|
params: Record<string, unknown>,
|
|
63
|
-
): Promise<
|
|
54
|
+
): Promise<TreeSnapshot> {
|
|
64
55
|
const dir = freshCwd();
|
|
65
56
|
const prev = process.cwd();
|
|
66
57
|
process.chdir(dir);
|
|
67
58
|
try {
|
|
68
59
|
const outcome = await executeVerb(
|
|
69
|
-
|
|
60
|
+
createVerbs[kind] as VerbSpec,
|
|
70
61
|
params,
|
|
71
62
|
{ dryRun: false, undo: false, yes: true },
|
|
72
63
|
bootRuntime(FLAGS, dir),
|
|
@@ -75,44 +66,38 @@ async function producePragma(
|
|
|
75
66
|
} finally {
|
|
76
67
|
process.chdir(prev);
|
|
77
68
|
}
|
|
78
|
-
return
|
|
69
|
+
return snapshotTree(dir);
|
|
79
70
|
}
|
|
80
71
|
|
|
81
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Producer (2): the shared conformance REFERENCE, over pragma's own generator.
|
|
74
|
+
*
|
|
75
|
+
* The fixture names its generator logically; `pickGenerator` is what turns that
|
|
76
|
+
* into the bundled definition. The suite never imports a generator itself —
|
|
77
|
+
* summon-core sits below both bins.
|
|
78
|
+
*/
|
|
82
79
|
async function produceSummon(
|
|
83
80
|
kind: CreateKind,
|
|
84
81
|
framework: string,
|
|
85
|
-
answers: Record<string, unknown
|
|
86
|
-
): Promise<
|
|
82
|
+
answers: Readonly<Record<string, unknown>>,
|
|
83
|
+
): Promise<TreeSnapshot> {
|
|
87
84
|
const { pickGenerator } = await import("./pickGenerator.js");
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
createGeneratorStamp,
|
|
93
|
-
createStampOnEffectStart,
|
|
94
|
-
} = await import("@canonical/summon-core");
|
|
95
|
-
const generator = pickGenerator(kind, { framework });
|
|
96
|
-
const dir = freshCwd();
|
|
97
|
-
await runGeneratorTask(
|
|
98
|
-
execute(generator, { prompt: autoPrompt(answers), params: answers }),
|
|
99
|
-
{
|
|
100
|
-
cwd: dir,
|
|
101
|
-
promptHandler: autoPrompt(answers),
|
|
102
|
-
onEffectStart: createStampOnEffectStart(createGeneratorStamp(generator)),
|
|
103
|
-
onLog: () => {},
|
|
104
|
-
},
|
|
105
|
-
);
|
|
106
|
-
return snapshot(dir);
|
|
85
|
+
return produceReference({
|
|
86
|
+
generator: pickGenerator(kind, { framework }),
|
|
87
|
+
answers,
|
|
88
|
+
});
|
|
107
89
|
}
|
|
108
90
|
|
|
109
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* One golden case: the shared fixture, plus what only pragma knows — which
|
|
93
|
+
* bundled generator the fixture's id names, and the CLI param names the create
|
|
94
|
+
* verb takes for the same answers.
|
|
95
|
+
*/
|
|
110
96
|
interface Case {
|
|
111
|
-
readonly
|
|
97
|
+
readonly fixture: string;
|
|
112
98
|
readonly kind: CreateKind;
|
|
113
99
|
readonly framework: string;
|
|
114
100
|
readonly params: Record<string, unknown>;
|
|
115
|
-
readonly answers: Record<string, unknown>;
|
|
116
101
|
}
|
|
117
102
|
|
|
118
103
|
const componentAnswers = {
|
|
@@ -123,7 +108,7 @@ const componentAnswers = {
|
|
|
123
108
|
|
|
124
109
|
const cases: Case[] = [
|
|
125
110
|
{
|
|
126
|
-
|
|
111
|
+
fixture: "component/react",
|
|
127
112
|
kind: "component",
|
|
128
113
|
framework: "react",
|
|
129
114
|
params: {
|
|
@@ -131,10 +116,9 @@ const cases: Case[] = [
|
|
|
131
116
|
componentPath: "src/components/Button",
|
|
132
117
|
...componentAnswers,
|
|
133
118
|
},
|
|
134
|
-
answers: { componentPath: "src/components/Button", ...componentAnswers },
|
|
135
119
|
},
|
|
136
120
|
{
|
|
137
|
-
|
|
121
|
+
fixture: "component/svelte",
|
|
138
122
|
kind: "component",
|
|
139
123
|
framework: "svelte",
|
|
140
124
|
params: {
|
|
@@ -142,10 +126,9 @@ const cases: Case[] = [
|
|
|
142
126
|
componentPath: "src/lib/Button",
|
|
143
127
|
...componentAnswers,
|
|
144
128
|
},
|
|
145
|
-
answers: { componentPath: "src/lib/Button", ...componentAnswers },
|
|
146
129
|
},
|
|
147
130
|
{
|
|
148
|
-
|
|
131
|
+
fixture: "component/lit",
|
|
149
132
|
kind: "component",
|
|
150
133
|
framework: "lit",
|
|
151
134
|
params: {
|
|
@@ -153,10 +136,9 @@ const cases: Case[] = [
|
|
|
153
136
|
componentPath: "src/lib/Button",
|
|
154
137
|
...componentAnswers,
|
|
155
138
|
},
|
|
156
|
-
answers: { componentPath: "src/lib/Button", ...componentAnswers },
|
|
157
139
|
},
|
|
158
140
|
{
|
|
159
|
-
|
|
141
|
+
fixture: "package",
|
|
160
142
|
kind: "package",
|
|
161
143
|
framework: "",
|
|
162
144
|
params: {
|
|
@@ -169,54 +151,53 @@ const cases: Case[] = [
|
|
|
169
151
|
withPrTemplate: false,
|
|
170
152
|
runInstall: false,
|
|
171
153
|
},
|
|
172
|
-
answers: {
|
|
173
|
-
name: "@canonical/my-lib",
|
|
174
|
-
type: "library",
|
|
175
|
-
description: "A library.",
|
|
176
|
-
withReact: false,
|
|
177
|
-
withStorybook: false,
|
|
178
|
-
withCli: false,
|
|
179
|
-
withPrTemplate: false,
|
|
180
|
-
runInstall: false,
|
|
181
|
-
},
|
|
182
154
|
},
|
|
183
155
|
{
|
|
184
|
-
|
|
156
|
+
fixture: "application",
|
|
185
157
|
kind: "application",
|
|
186
158
|
framework: "",
|
|
159
|
+
// The pragma path receives the CLI `--with-X` params (AV-228 B8); the shared
|
|
160
|
+
// fixture carries the generator's bare prompt names. runCreate's boundary
|
|
161
|
+
// remap (`withSsr` -> `ssr`, ...) makes both produce the identical tree —
|
|
162
|
+
// which is exactly what this case exists to prove.
|
|
187
163
|
params: {
|
|
188
164
|
appPath: "my-app",
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
runInstall: false,
|
|
194
|
-
},
|
|
195
|
-
answers: {
|
|
196
|
-
appPath: "my-app",
|
|
197
|
-
ssr: true,
|
|
198
|
-
router: true,
|
|
199
|
-
forms: true,
|
|
200
|
-
relay: false,
|
|
165
|
+
withSsr: true,
|
|
166
|
+
withRouter: true,
|
|
167
|
+
withForms: true,
|
|
168
|
+
withRelay: false,
|
|
201
169
|
runInstall: false,
|
|
202
170
|
},
|
|
203
171
|
},
|
|
204
172
|
];
|
|
205
173
|
|
|
206
|
-
describe("byte-equality goldens — pragma create
|
|
174
|
+
describe("byte-equality goldens — pragma create \u2261 the conformance reference (PROTECTED)", () => {
|
|
175
|
+
it("covers every shared conformance fixture", () => {
|
|
176
|
+
// The suite's fixture list is the contract; a fixture added there and not
|
|
177
|
+
// wired here would silently go unchecked on pragma's side.
|
|
178
|
+
expect(cases.map((entry) => entry.fixture)).toEqual(
|
|
179
|
+
CONFORMANCE_FIXTURES.map((entry) => entry.name),
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
207
183
|
for (const testCase of cases) {
|
|
208
|
-
it(`${testCase.
|
|
184
|
+
it(`${testCase.fixture}: the kernel path matches the reference byte for byte`, async () => {
|
|
185
|
+
const shared = CONFORMANCE_FIXTURES.find(
|
|
186
|
+
(entry) => entry.name === testCase.fixture,
|
|
187
|
+
);
|
|
188
|
+
if (!shared) throw new Error(`no fixture "${testCase.fixture}"`);
|
|
209
189
|
const pragma = await producePragma(testCase.kind, testCase.params);
|
|
210
|
-
const
|
|
190
|
+
const reference = await produceSummon(
|
|
211
191
|
testCase.kind,
|
|
212
192
|
testCase.framework,
|
|
213
|
-
|
|
193
|
+
shared.answers,
|
|
214
194
|
);
|
|
215
195
|
expect(pragma.size).toBeGreaterThan(0);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
196
|
+
const diff = diffTrees(pragma, reference);
|
|
197
|
+
expect(
|
|
198
|
+
isIdentical(diff),
|
|
199
|
+
formatTreeDiff(diff, "pragma create", "the conformance reference"),
|
|
200
|
+
).toBe(true);
|
|
220
201
|
});
|
|
221
202
|
}
|
|
222
203
|
});
|