@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.
Files changed (250) hide show
  1. package/README.md +7 -7
  2. package/dist/pragma +0 -0
  3. package/package.json +18 -15
  4. package/pragma.conf.ts +664 -0
  5. package/src/bin.ts +13 -4
  6. package/src/capabilities/block.parity.test.ts +250 -0
  7. package/src/capabilities/capabilities/capabilities.render.ts +3 -2
  8. package/src/capabilities/capabilities/capabilities.verb.ts +31 -13
  9. package/src/capabilities/capabilities/catalog.ts +18 -10
  10. package/src/capabilities/capabilities/hints.ts +13 -19
  11. package/src/capabilities/colophon/collectColophon.ts +34 -19
  12. package/src/capabilities/colophon/colophon.verb.ts +8 -4
  13. package/src/capabilities/colophon/types.ts +16 -7
  14. package/src/capabilities/config/collectConfigShow.test.ts +57 -0
  15. package/src/capabilities/config/collectConfigShow.ts +41 -4
  16. package/src/capabilities/config/fields.ts +0 -27
  17. package/src/capabilities/config/set.verb.ts +7 -3
  18. package/src/capabilities/config/show.render.test.ts +77 -5
  19. package/src/capabilities/config/show.render.ts +7 -12
  20. package/src/capabilities/config/show.verb.ts +4 -3
  21. package/src/capabilities/config/types.ts +8 -0
  22. package/src/capabilities/create/byteEquality.test.ts +78 -100
  23. package/src/capabilities/create/compiledCreate.subprocess.test.ts +52 -15
  24. package/src/capabilities/create/constants.ts +75 -0
  25. package/src/capabilities/create/create.mcp.test.ts +2 -2
  26. package/src/capabilities/create/create.test.ts +162 -15
  27. package/src/capabilities/create/create.verb.ts +140 -69
  28. package/src/capabilities/create/index.ts +2 -10
  29. package/src/capabilities/create/pickGenerator.ts +34 -28
  30. package/src/capabilities/create/templates.embedded.generated.ts +4 -29
  31. package/src/capabilities/create/types.ts +10 -6
  32. package/src/capabilities/{standard/parity.test.ts → distribution.parity.test.ts} +24 -14
  33. package/src/capabilities/distribution.test.ts +120 -0
  34. package/src/capabilities/distribution.ts +59 -0
  35. package/src/capabilities/doctor/checks/checkConfigFile.ts +6 -5
  36. package/src/capabilities/doctor/checks/checkKeStore.ts +2 -2
  37. package/src/capabilities/doctor/checks/checkMcpConfigured.ts +7 -6
  38. package/src/capabilities/doctor/checks/checkPackageRefs.ts +79 -45
  39. package/src/capabilities/doctor/checks/checkPragmaVersion.ts +3 -2
  40. package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +61 -11
  41. package/src/capabilities/doctor/checks/checkShellCompletions.ts +63 -23
  42. package/src/capabilities/doctor/checks/checkSkillsSymlinked.ts +3 -2
  43. package/src/capabilities/doctor/doctor.render.test.ts +6 -6
  44. package/src/capabilities/doctor/doctor.render.ts +2 -1
  45. package/src/capabilities/doctor/doctor.test.ts +37 -8
  46. package/src/capabilities/doctor/doctor.verb.ts +6 -2
  47. package/src/capabilities/doctor/runChecks.ts +5 -5
  48. package/src/capabilities/doctor/types.ts +1 -1
  49. package/src/capabilities/emptyRecovery.test.ts +32 -15
  50. package/src/capabilities/graph/inspect.verb.ts +3 -2
  51. package/src/capabilities/graph/query.verb.ts +3 -2
  52. package/src/capabilities/graph/runQuery.ts +8 -5
  53. package/src/capabilities/index.ts +22 -18
  54. package/src/capabilities/info/collectInfo.ts +10 -6
  55. package/src/capabilities/info/info.render.ts +3 -2
  56. package/src/capabilities/info/info.verb.ts +3 -2
  57. package/src/capabilities/lazy.test.ts +93 -2
  58. package/src/capabilities/ontology/verbs.ts +21 -21
  59. package/src/capabilities/prompt/prompt.test.ts +12 -6
  60. package/src/capabilities/prompt/verbs.ts +24 -11
  61. package/src/capabilities/resources/provider.ts +30 -11
  62. package/src/capabilities/resources/resources.test.ts +85 -29
  63. package/src/capabilities/setup/operations/setupGenerator.ts +16 -9
  64. package/src/capabilities/setup/operations/setupMcp.ts +2 -2
  65. package/src/capabilities/setup/operations/setupSkills.ts +3 -3
  66. package/src/capabilities/setup/setup.verb.ts +12 -5
  67. package/src/capabilities/setup/shell.ts +29 -3
  68. package/src/capabilities/skill/discover.ts +11 -5
  69. package/src/capabilities/skill/render.ts +4 -5
  70. package/src/capabilities/skill/verbs.ts +7 -7
  71. package/src/capabilities/sources/collectStatus.ts +55 -50
  72. package/src/capabilities/sources/index.ts +1 -1
  73. package/src/capabilities/sources/installSkills.ts +2 -2
  74. package/src/capabilities/sources/runUpdate.ts +113 -122
  75. package/src/capabilities/sources/sources.test.ts +111 -117
  76. package/src/capabilities/sources/status.render.test.ts +53 -24
  77. package/src/capabilities/sources/status.render.ts +24 -29
  78. package/src/capabilities/sources/status.verb.ts +15 -8
  79. package/src/capabilities/sources/types.ts +18 -25
  80. package/src/capabilities/sources/update.render.ts +9 -2
  81. package/src/capabilities/sources/update.verb.ts +12 -23
  82. package/src/capabilities/surface.test.ts +33 -10
  83. package/src/capabilities/tier.parity.test.ts +144 -0
  84. package/src/capabilities/upgrade/upgrade.verb.ts +7 -3
  85. package/src/constants.test.ts +8 -6
  86. package/src/constants.ts +47 -21
  87. package/src/identity.test.ts +333 -0
  88. package/src/index.ts +2 -2
  89. package/src/kernel/completion/__snapshots__/emitScripts.test.ts.snap +5 -2
  90. package/src/kernel/completion/emitScripts.test.ts +1 -1
  91. package/src/kernel/completion/emitScripts.ts +4 -2
  92. package/src/kernel/completion/entitySource.test.ts +185 -41
  93. package/src/kernel/completion/entitySource.ts +117 -107
  94. package/src/kernel/completion/model.test.ts +1 -1
  95. package/src/kernel/completion/model.ts +11 -0
  96. package/src/kernel/completion/safety.test.ts +82 -36
  97. package/src/kernel/completion/shellDrive.test.ts +592 -0
  98. package/src/kernel/completion/templates/fish.ts +28 -6
  99. package/src/kernel/completion/types.ts +3 -3
  100. package/src/kernel/config/__snapshots__/firstRun.test.ts.snap +1 -1
  101. package/src/kernel/config/defaults.test.ts +85 -0
  102. package/src/kernel/config/defaults.ts +12 -23
  103. package/src/kernel/config/evaluateProjectConfig.ts +2 -3
  104. package/src/kernel/config/findProjectConfig.ts +4 -3
  105. package/src/kernel/config/firstRun.ts +12 -5
  106. package/src/kernel/config/globalConfig.ts +2 -2
  107. package/src/kernel/config/index.ts +4 -5
  108. package/src/kernel/config/paths.ts +17 -17
  109. package/src/kernel/config/readConfig.test.ts +242 -6
  110. package/src/kernel/config/readConfig.ts +8 -8
  111. package/src/kernel/config/schema.test.ts +50 -0
  112. package/src/kernel/config/schema.ts +97 -10
  113. package/src/kernel/config/types.ts +73 -19
  114. package/src/kernel/copy.test.ts +453 -0
  115. package/src/kernel/error/PragmaError.test.ts +1 -1
  116. package/src/kernel/error/constants.ts +3 -2
  117. package/src/kernel/error/index.ts +1 -1
  118. package/src/kernel/error/recovery.test.ts +22 -45
  119. package/src/kernel/error/recovery.ts +22 -27
  120. package/src/kernel/error/types.ts +5 -4
  121. package/src/kernel/packs/collect.test.ts +195 -11
  122. package/src/kernel/packs/collect.ts +213 -58
  123. package/src/kernel/packs/compile.test.ts +163 -7
  124. package/src/kernel/packs/compile.ts +15 -12
  125. package/src/kernel/packs/disclosure.test.ts +5 -2
  126. package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +11 -10
  127. package/src/kernel/packs/graphqlSource.test.ts +6 -3
  128. package/src/kernel/packs/iri.ts +5 -7
  129. package/src/kernel/packs/renderPack.ts +5 -3
  130. package/src/kernel/packs/resolveEntity.ts +21 -17
  131. package/src/kernel/packs/runBodies.ts +15 -14
  132. package/src/kernel/packs/schema.ts +96 -10
  133. package/src/kernel/packs/sparql/runSelect.test.ts +104 -10
  134. package/src/kernel/packs/sparql/runSelect.ts +73 -34
  135. package/src/kernel/packs/toolDescription.test.ts +10 -2
  136. package/src/kernel/packs/types.ts +39 -4
  137. package/src/kernel/packs/uniqueness.ts +4 -4
  138. package/src/kernel/project/cli/buildProgram.test.ts +9 -4
  139. package/src/kernel/project/cli/dispatch.test.ts +67 -0
  140. package/src/kernel/project/cli/dispatch.ts +34 -12
  141. package/src/kernel/project/cli/helpFormat.ts +1 -1
  142. package/src/kernel/project/cli/rootHelp.ts +105 -105
  143. package/src/kernel/project/mcp/buildServer.ts +11 -6
  144. package/src/kernel/project/mcp/instructions.ts +11 -6
  145. package/src/kernel/project/mcp/parity.test.ts +39 -1
  146. package/src/kernel/project/mcp/prompts/prompts.test.ts +120 -5
  147. package/src/kernel/project/mcp/prompts/provider.ts +22 -8
  148. package/src/kernel/project/mcp/prompts/source.ts +68 -67
  149. package/src/kernel/project/mcp/registerVerb.ts +25 -6
  150. package/src/kernel/project/mcp/serve.ts +11 -3
  151. package/src/kernel/project/mcp/toolDescriptions.test.ts +6 -2
  152. package/src/kernel/render/disclosure.ts +4 -2
  153. package/src/kernel/render/prefixes.test.ts +36 -0
  154. package/src/kernel/render/prefixes.ts +40 -13
  155. package/src/kernel/render/renderers.test.ts +1 -1
  156. package/src/kernel/runtime/graphpack/build.ts +29 -3
  157. package/src/kernel/runtime/graphpack/buildIndex.test.ts +46 -0
  158. package/src/kernel/runtime/graphpack/buildIndex.ts +52 -17
  159. package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +5 -5
  160. package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +3 -3
  161. package/src/kernel/runtime/graphpack/embedded/pack.stories.generated.ts +3 -0
  162. package/src/kernel/runtime/graphpack/embedded.ts +37 -11
  163. package/src/kernel/runtime/graphpack/graphpack.test.ts +205 -5
  164. package/src/kernel/runtime/graphpack/hash.ts +3 -2
  165. package/src/kernel/runtime/graphpack/index.ts +1 -1
  166. package/src/kernel/runtime/graphpack/manifest.ts +114 -12
  167. package/src/kernel/runtime/graphpack/read.ts +4 -9
  168. package/src/kernel/runtime/graphpack/schemas.ts +74 -0
  169. package/src/kernel/runtime/graphpack/stories.ts +84 -0
  170. package/src/kernel/runtime/graphpack/types.ts +61 -48
  171. package/src/kernel/runtime/paths.ts +64 -15
  172. package/src/kernel/runtime/probe.test.ts +8 -4
  173. package/src/kernel/runtime/readEntity.ts +6 -5
  174. package/src/kernel/runtime/refs/gitOps.ts +1 -19
  175. package/src/kernel/runtime/refs/parseRef.ts +7 -7
  176. package/src/kernel/runtime/refs/resolve.ts +78 -62
  177. package/src/kernel/runtime/resolveSources.test.ts +63 -24
  178. package/src/kernel/runtime/resolveSources.ts +36 -25
  179. package/src/kernel/runtime/storeReadiness.ts +9 -8
  180. package/src/kernel/runtime/storeless.test.ts +1 -1
  181. package/src/kernel/runtime/wasmEmbed.test.ts +22 -19
  182. package/src/kernel/spec/emitReference.test.ts +3 -3
  183. package/src/kernel/spec/emitReference.ts +144 -11
  184. package/src/kernel/spec/emitSurface.ts +9 -5
  185. package/src/kernel/spec/surfaceConformance.test.ts +2 -2
  186. package/src/kernel/spec/surfaceConformance.ts +8 -0
  187. package/src/kernel/spec/types.ts +29 -9
  188. package/src/kernel/spec/validate.ts +2 -1
  189. package/src/kernel/vocabulary.test.ts +164 -0
  190. package/src/kernel/vocabulary.ts +146 -0
  191. package/src/testing/PARITY_GAPS.ts +8 -2
  192. package/src/testing/behavioral/README.md +3 -3
  193. package/src/testing/behavioral/completion.test.ts +19 -6
  194. package/src/testing/behavioral/errorMatrix.mcp.test.ts +4 -3
  195. package/src/testing/behavioral/errorMatrix.storeless.test.ts +1 -1
  196. package/src/testing/behavioral/exitCodes.e2e.test.ts +6 -5
  197. package/src/testing/behavioral/harness.foundation.test.ts +14 -5
  198. package/src/testing/behavioral/journeys.cli.test.ts +116 -75
  199. package/src/testing/behavioral/journeys.defaultPack.test.ts +82 -176
  200. package/src/testing/behavioral/journeys.firstInstall.test.ts +167 -0
  201. package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +9 -6
  202. package/src/testing/behavioral/journeys.packageStories.test.ts +188 -0
  203. package/src/testing/behavioral/liveReadSurface.ts +4 -3
  204. package/src/testing/behavioral/mcpSurface.test.ts +9 -4
  205. package/src/testing/behavioral/staleCommands.test.ts +10 -0
  206. package/src/testing/eval/__snapshots__/eval.test.ts.snap +7 -7
  207. package/src/testing/eval/cases/assembly.ts +13 -6
  208. package/src/testing/eval/cases/effectful.ts +25 -13
  209. package/src/testing/eval/cases/readNouns.ts +22 -20
  210. package/src/testing/eval/cases/stable.ts +5 -1
  211. package/src/testing/eval/eval.test.ts +7 -1
  212. package/src/testing/fixtures/fixtureCapability.ts +45 -1
  213. package/src/testing/fixtures/graph/canonical.ts +6 -3
  214. package/src/testing/fixtures/graph/defaultPack.ts +6 -5
  215. package/src/testing/fixtures/graph/owlExport.ts +7 -5
  216. package/src/testing/helpers/fixtureGraph.ts +33 -16
  217. package/src/testing/helpers/packRuntime.ts +2 -3
  218. package/src/testing/helpers/projectCli.ts +2 -1
  219. package/src/testing/helpers/projectMcp.ts +6 -0
  220. package/src/testing/perf/budgets.test.ts +4 -0
  221. package/src/testing/perf/budgets.ts +22 -7
  222. package/src/testing/perf/globalSetup.ts +121 -6
  223. package/src/types.ts +2 -2
  224. package/src/capabilities/block/blockList.test.ts +0 -79
  225. package/src/capabilities/block/blockList.verb.ts +0 -163
  226. package/src/capabilities/block/index.ts +0 -25
  227. package/src/capabilities/block/pack.ts +0 -166
  228. package/src/capabilities/block/parity.test.ts +0 -187
  229. package/src/capabilities/block/tierChain.ts +0 -78
  230. package/src/capabilities/colophon/pragmaColophon.ts +0 -66
  231. package/src/capabilities/modifier/index.ts +0 -15
  232. package/src/capabilities/modifier/pack.ts +0 -64
  233. package/src/capabilities/standard/index.ts +0 -18
  234. package/src/capabilities/standard/pack.ts +0 -128
  235. package/src/capabilities/tier/index.ts +0 -19
  236. package/src/capabilities/tier/lookup.render.test.ts +0 -72
  237. package/src/capabilities/tier/lookup.render.ts +0 -59
  238. package/src/capabilities/tier/lookup.test.ts +0 -83
  239. package/src/capabilities/tier/lookup.verb.ts +0 -44
  240. package/src/capabilities/tier/pack.ts +0 -28
  241. package/src/capabilities/tier/runLookup.ts +0 -87
  242. package/src/capabilities/token/addConfig.render.ts +0 -27
  243. package/src/capabilities/token/addConfig.test.ts +0 -62
  244. package/src/capabilities/token/addConfig.verb.ts +0 -40
  245. package/src/capabilities/token/index.ts +0 -19
  246. package/src/capabilities/token/pack.ts +0 -58
  247. package/src/capabilities/token/runAddConfig.ts +0 -95
  248. package/src/kernel/completion/bashDrive.test.ts +0 -73
  249. package/src/kernel/runtime/graphpack/embedded/sample.ttl +0 -39
  250. package/src/kernel/runtime/lock.ts +0 -90
@@ -2,28 +2,37 @@
2
2
  * Data shapes for `pragma colophon`.
3
3
  *
4
4
  * A colophon (the printer's end-note on how a book is made) for the toolchain:
5
- * one section narrating how pragma itself is built, followed by one section per
6
- * active pack/domain that declares a `colophon`. Storeless and read-only.
5
+ * one section narrating how the distribution itself is built — declared in its
6
+ * config, not authored in code — followed by one section per active pack/domain
7
+ * that declares a `colophon`. Storeless and read-only.
7
8
  */
8
9
 
9
- /** One colophon section — pragma's own, or an active pack's domain story. */
10
+ /** One colophon section — the distribution's own, or an active pack's story. */
10
11
  export interface ColophonSection {
11
- /** Whether this is pragma's built-in section or an active pack's. */
12
+ /**
13
+ * Whether this is the distribution's declared section or an active pack's.
14
+ * `"pragma"` is a FROZEN JSON-visible discriminant (wire compatibility, like
15
+ * the `pragma:` resource scheme) — it does not track the distribution's
16
+ * name; a fork's own section still carries `kind: "pragma"`.
17
+ */
12
18
  readonly kind: "pragma" | "pack";
13
- /** Section heading — `"pragma"`, or the pack's noun/name. */
19
+ /** Section heading — the distribution's name, or the pack's noun/name. */
14
20
  readonly title: string;
15
21
  /**
16
22
  * The authored Markdown BODY (no leading H1 — the renderer supplies the
17
23
  * heading from {@link title}, so a section is never double-titled).
18
24
  */
19
25
  readonly markdown: string;
20
- /** Optional condensed body for `--format llm` (pragma supplies one). */
26
+ /** Optional condensed body for `--format llm` (the declaration's `summary`). */
21
27
  readonly summary?: string;
22
28
  /** Provenance: `"built-in"`, or `"pack:<name>"`. */
23
29
  readonly source?: string;
24
30
  }
25
31
 
26
- /** The full `colophon` payload: pragma's section first, then active packs'. */
32
+ /**
33
+ * The full `colophon` payload: the distribution's declared section first (when
34
+ * its config declares one), then active packs'.
35
+ */
27
36
  export interface ColophonData {
28
37
  readonly sections: readonly ColophonSection[];
29
38
  }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * `config show` payload projection — declared story BODIES never ship.
3
+ *
4
+ * MCP returns the JSON formatter's output verbatim, so anything in this payload
5
+ * is tokens in every `config_show` tool call. The distribution declares five
6
+ * read stories on its packs, whose bodies are SPARQL; carried through, they take
7
+ * the payload from ~1.3 KB to ~11 KB — larger than `capabilities`, the discovery
8
+ * tool, for the least useful content in the surface.
9
+ */
10
+
11
+ import { mkdtempSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { describe, expect, it } from "vitest";
15
+ import { bootRuntime } from "../../kernel/runtime/boot.js";
16
+ import type { GlobalFlags } from "../../kernel/runtime/types.js";
17
+ import { collectConfigShow } from "./collectConfigShow.js";
18
+
19
+ const FLAGS: GlobalFlags = {
20
+ llm: false,
21
+ autoLlm: false,
22
+ format: "json",
23
+ verbose: false,
24
+ };
25
+
26
+ describe("config show payload", () => {
27
+ it("names the declared packs but carries no story bodies", async () => {
28
+ const cwd = mkdtempSync(join(tmpdir(), "pragma-config-show-"));
29
+ const data = await collectConfigShow(bootRuntime(FLAGS, cwd));
30
+
31
+ // The pack declarations themselves are still fully reported…
32
+ expect(
33
+ data.config.packs?.map((pack) =>
34
+ typeof pack === "string" ? pack : pack.name,
35
+ ),
36
+ ).toEqual([
37
+ "@canonical/design-system",
38
+ "@canonical/anatomy-dsl",
39
+ "@canonical/code-standards",
40
+ ]);
41
+ for (const pack of data.config.packs ?? []) {
42
+ expect(
43
+ typeof pack === "string" ? undefined : pack.stories,
44
+ ).toBeUndefined();
45
+ }
46
+ expect(data.config.stories).toBeUndefined();
47
+
48
+ // …and provenance stays honest: the payload still says where they came from.
49
+ expect(data.origins.packs).toBe("default");
50
+ expect(data.origins.stories).toBe("default");
51
+
52
+ // The sharp end: no query text reaches the agent surface.
53
+ const payload = JSON.stringify(data);
54
+ expect(payload).not.toContain("SELECT ?");
55
+ expect(payload.length).toBeLessThan(3000);
56
+ });
57
+ });
@@ -1,15 +1,52 @@
1
1
  /**
2
2
  * Collect the `config show` payload — the verb's run body (lazily imported).
3
3
  *
4
- * Storeless: read the layered config and pass it through with its provenance.
5
- * Dynamic-imported by the spec so building the tree never pulls the config
6
- * reader (or zod) onto the fast path.
4
+ * Storeless: read the layered config and pass it through with its provenance,
5
+ * minus the declared story BODIES (see {@link withoutStoryBodies}). Dynamic-
6
+ * imported by the spec so building the tree never pulls the config reader (or
7
+ * zod) onto the fast path.
7
8
  */
8
9
 
9
10
  import { readConfig } from "../../kernel/config/readConfig.js";
11
+ import type {
12
+ PackDeclaration,
13
+ PragmaConfig,
14
+ } from "../../kernel/config/types.js";
10
15
  import type { PragmaRuntime } from "../../kernel/runtime/types.js";
11
16
  import type { ConfigShowData } from "./types.js";
12
17
 
18
+ /** A pack declaration with any declared story bodies dropped. */
19
+ function nameAndSourceOnly(pack: PackDeclaration): PackDeclaration {
20
+ if (typeof pack === "string") return pack;
21
+ return {
22
+ name: pack.name,
23
+ ...(pack.source === undefined ? {} : { source: pack.source }),
24
+ };
25
+ }
26
+
27
+ /**
28
+ * The effective config with declared story BODIES dropped — `packs` entries keep
29
+ * `{ name, source }`, and the top-level `stories` array is omitted.
30
+ *
31
+ * A PROJECTION of the payload, not a hiding of config: `origins` still reports
32
+ * where `packs` and `stories` came from, the plain and llm renders already print
33
+ * pack NAMES only, and `pragma capabilities` lists the verbs the stories
34
+ * produce. It exists because the bodies are SPARQL — the distribution's own five
35
+ * stories take `config show --format json` from 1.3 KB to 11 KB, and MCP returns
36
+ * the JSON formatter's output, so every `config_show` tool call would carry
37
+ * ~2.7k tokens of query text: the largest payload in the surface, for its least
38
+ * useful content.
39
+ */
40
+ function withoutStoryBodies(config: PragmaConfig): PragmaConfig {
41
+ const { stories, ...rest } = config;
42
+ return {
43
+ ...rest,
44
+ ...(config.packs === undefined
45
+ ? {}
46
+ : { packs: config.packs.map(nameAndSourceOnly) }),
47
+ };
48
+ }
49
+
13
50
  /**
14
51
  * Assemble the resolved config with provenance for the current runtime.
15
52
  *
@@ -22,7 +59,7 @@ export async function collectConfigShow(
22
59
  ): Promise<ConfigShowData> {
23
60
  const layers = await readConfig(runtime.cwd);
24
61
  return {
25
- config: layers.config,
62
+ config: withoutStoryBodies(layers.config),
26
63
  origins: layers.origins,
27
64
  ...(layers.project.path ? { projectConfigPath: layers.project.path } : {}),
28
65
  globalConfigPath: layers.global.path,
@@ -21,14 +21,8 @@ export interface ConfigFieldSpec {
21
21
  readonly kind: "string" | "enum";
22
22
  /** The allowed values for an enum field. */
23
23
  readonly values?: readonly string[];
24
- /** One-line field summary. */
25
- readonly summary: string;
26
- /** Extended help doc. */
27
- readonly doc: string;
28
24
  /** Reserved values that REMOVE the field instead of setting it. */
29
25
  readonly resetSentinel?: readonly string[];
30
- /** Field help examples. */
31
- readonly examples: readonly { cmd: string; note?: string }[];
32
26
  }
33
27
 
34
28
  /**
@@ -44,38 +38,17 @@ export const CONFIG_FIELDS: readonly ConfigFieldSpec[] = [
44
38
  positional: "path",
45
39
  kind: "string",
46
40
  resetSentinel: ["none", "default", "-"],
47
- summary: "Set the active design-system tier.",
48
- doc: "Writes the `tier` field to the global config. Pass `none`, `default`, or `-` to clear it. Written to the global layer only — project configs are authored by hand.",
49
- examples: [
50
- {
51
- cmd: "pragma config set tier apps/lxd",
52
- note: "scope reads to a tier",
53
- },
54
- { cmd: "pragma config set tier none", note: "clear the tier" },
55
- ],
56
41
  },
57
42
  {
58
43
  field: "channel",
59
44
  positional: "name",
60
45
  kind: "enum",
61
46
  values: CHANNELS,
62
- summary: "Set the release channel controlling component visibility.",
63
- doc: "Writes the `channel` field to the global config. Reset by setting the default, `normal`.",
64
- examples: [
65
- { cmd: "pragma config set channel experimental" },
66
- { cmd: "pragma config set channel normal", note: "back to the default" },
67
- ],
68
47
  },
69
48
  {
70
49
  field: "detail",
71
50
  positional: "level",
72
51
  kind: "enum",
73
52
  values: DETAIL_LEVELS,
74
- summary: "Set the default progressive-disclosure level.",
75
- doc: "Writes the `detail` field to the global config. Reset by setting the default, `standard`.",
76
- examples: [
77
- { cmd: "pragma config set detail detailed" },
78
- { cmd: "pragma config set detail standard", note: "back to the default" },
79
- ],
80
53
  },
81
54
  ];
@@ -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
- { cmd: "pragma config set tier apps/lxd", note: "scope reads to a tier" },
50
- { cmd: "pragma config set channel experimental" },
51
- { cmd: "pragma config set tier none", note: "clear the tier" },
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,
@@ -1,6 +1,8 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { type RenderStyle, styleFor } from "../../kernel/render/style.js";
3
- import { renderConfigShowPlain } from "./show.render.js";
3
+ import { emitReference } from "../../kernel/spec/emitReference.js";
4
+ import { capabilities } from "../index.js";
5
+ import { configShowFormatters, renderConfigShowPlain } from "./show.render.js";
4
6
  import type { ConfigShowData } from "./types.js";
5
7
 
6
8
  const DATA: ConfigShowData = {
@@ -8,16 +10,15 @@ const DATA: ConfigShowData = {
8
10
  tier: "apps/lxd",
9
11
  channel: "normal",
10
12
  detail: "standard",
11
- packages: ["@canonical/ds"],
13
+ packs: ["@canonical/ds"],
12
14
  },
13
15
  origins: {
14
16
  tier: "project",
15
17
  channel: "default",
16
18
  detail: "default",
17
- packages: "global",
19
+ packs: "global",
18
20
  stories: "default",
19
21
  prefixes: "default",
20
- prompts: "default",
21
22
  },
22
23
  globalConfigPath: "/home/u/.config/pragma/config.json",
23
24
  projectConfigPath: "/repo/pragma.config.ts",
@@ -42,7 +43,7 @@ describe("renderConfigShowPlain", () => {
42
43
  "tier: apps/lxd [project]",
43
44
  "channel: normal",
44
45
  "detail: standard",
45
- "packages: @canonical/ds [global]",
46
+ "packs: @canonical/ds [global]",
46
47
  "global config: /home/u/.config/pragma/config.json",
47
48
  "project config: /repo/pragma.config.ts",
48
49
  ].join("\n"),
@@ -62,4 +63,75 @@ describe("renderConfigShowPlain", () => {
62
63
  );
63
64
  expect(out).not.toContain("<d> [default]</d>");
64
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
+ });
65
137
  });
@@ -16,10 +16,9 @@ function originMarker(origin: ConfigOrigin): string {
16
16
  return origin === "default" ? "" : ` [${origin}]`;
17
17
  }
18
18
 
19
- /** Summarize the `packages` list as a comma-separated set of names. */
20
- function packageNames(data: ConfigShowData): string {
21
- const packages = data.config.packages ?? [];
22
- 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) =>
23
22
  typeof entry === "string" ? entry : entry.name,
24
23
  );
25
24
  return names.length > 0 ? names.join(", ") : "(none)";
@@ -32,14 +31,10 @@ type ConfigRow = readonly [label: string, value: string, marker: string];
32
31
  function configRows(data: ConfigShowData): readonly ConfigRow[] {
33
32
  const { config, origins } = data;
34
33
  return [
35
- [
36
- "tier",
37
- config.tier ?? "(none — all tiers visible)",
38
- originMarker(origins.tier),
39
- ],
34
+ ["tier", config.tier ?? "(none)", originMarker(origins.tier)],
40
35
  ["channel", config.channel, originMarker(origins.channel)],
41
36
  ["detail", config.detail ?? "standard", originMarker(origins.detail)],
42
- ["packages", packageNames(data), originMarker(origins.packages)],
37
+ ["packs", entryNames(config.packs ?? []), originMarker(origins.packs)],
43
38
  [
44
39
  "global config",
45
40
  `${data.globalConfigPath}${data.globalExists ? "" : " (not found)"}`,
@@ -89,10 +84,10 @@ export const configShowFormatters: Formatters<ConfigShowData> = {
89
84
  const lines = [
90
85
  "## Configuration",
91
86
  "",
92
- `- **Tier:** ${config.tier ?? "none (all tiers)"}${originMarker(origins.tier)}`,
87
+ `- **Tier:** ${config.tier ?? "none"}${originMarker(origins.tier)}`,
93
88
  `- **Channel:** ${config.channel}${originMarker(origins.channel)}`,
94
89
  `- **Detail:** ${config.detail ?? "standard"}${originMarker(origins.detail)}`,
95
- `- **Packages:** ${packageNames(data)}${originMarker(origins.packages)}`,
90
+ `- **Packs:** ${entryNames(config.packs ?? [])}${originMarker(origins.packs)}`,
96
91
  `- **Global config:** \`${data.globalConfigPath}\``,
97
92
  ];
98
93
  if (data.projectConfigPath) {
@@ -5,6 +5,7 @@
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
11
  import { configSetVerb } from "./set.verb.js";
@@ -14,12 +15,12 @@ import type { ConfigShowData } from "./types.js";
14
15
  const showVerb: VerbSpec<Record<string, unknown>, ConfigShowData> = {
15
16
  path: ["config", "show"],
16
17
  summary: "Show the resolved config and per-field provenance.",
17
- doc: "Merges built-in defaults, the global XDG config, and the nearest pragma.config.ts, marking which layer supplied each value.",
18
+ doc: `Merges built-in defaults, the global XDG config, and the nearest ${PROJECT_CONFIG_FILENAME}, marking which layer supplied each value.`,
18
19
  params: [],
19
20
  output: { formatters: configShowFormatters },
20
21
  examples: [
21
- { cmd: "pragma config show" },
22
- { cmd: "pragma config show --format json" },
22
+ { cmd: `${BIN_NAME} config show` },
23
+ { cmd: `${BIN_NAME} config show --format json` },
23
24
  ],
24
25
  capability: {
25
26
  needsStore: false,
@@ -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;