@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
@@ -1,166 +0,0 @@
1
- /**
2
- * The bundled `block` pack — the lookup verb only.
3
- *
4
- * `block lookup` is served over the GraphQL fetch path (ONE generated document
5
- * over the `UIBlock` interface covering Component/Pattern/Layout/Subcomponent);
6
- * `block list` deliberately stays HAND-WRITTEN (tier-chain inheritance + channel
7
- * + `--all-tiers` — see ./blockList.verb). Base level mirrors the old summary
8
- * view (name/tier/summary); the default is `detailed`, matching the old CLI
9
- * which rendered anatomy and modifiers without a flag. A derived name that maps
10
- * onto no schema field is omitted (OPTIONAL parity), so a graph lacking
11
- * whenToUse/whenNotToUse degrades gracefully.
12
- *
13
- * Disclosure declares the FULL canonical ladder `[summary, standard, detailed]`
14
- * (B4), the same set `standard` declares, so a config `detail=standard` names a
15
- * level `block` advertises rather than one it silently accepts-then-degrades.
16
- * Block carries no `standard`-tier content of its own — gating is by canonical
17
- * index, so `standard` resolves to the base view — but the declared set now
18
- * matches its sibling reads. The per-noun DEFAULT stays domain-tuned (`block`
19
- * rich-by-default, `standard` terse-by-default); only the level SET is aligned.
20
- */
21
-
22
- import type { PackDefinition } from "../../kernel/packs/types.js";
23
-
24
- /**
25
- * The bundled design-system domain colophon — the ontology + graph story,
26
- * surfaced by `pragma colophon` after pragma's own. Authored on the flagship
27
- * UI-block noun because `block` most embodies the design system; it narrates the
28
- * DOMAIN (what the graph models), not the toolchain (pragma's built-in section).
29
- */
30
- const DESIGN_SYSTEM_COLOPHON = `The Canonical design system is a **knowledge graph**, not a component library.
31
- Every block, token, modifier, standard, and tier is a node in an RDF store,
32
- described by the \`ds:\` ontology and queried the same way whether you reach it
33
- over GraphQL or raw SPARQL.
34
-
35
- ## What the graph models
36
-
37
- - **Blocks** — components, patterns, layouts, and subcomponents (the \`ds:UIBlock\`
38
- family). A block carries its anatomy, guidelines, and \`when to use\` / \`when
39
- not to use\` narrative as graph properties, not prose in a wiki.
40
- - **Modifiers** — families of variant values (\`ds:hasModifierFamily\` →
41
- \`ds:hasModifier\`) a block composes, so a variant is a relationship, not a
42
- string.
43
- - **Tokens** — the themeable design values, resolved per theme.
44
- - **Standards** — the do / don't coding guidance, categorized and linked to the
45
- blocks they govern.
46
-
47
- ## How it fits together
48
-
49
- - **Tiers** are a hierarchy (\`global\` > \`apps\` > \`apps/lxd\`): a lower tier
50
- inherits and overrides the blocks of its ancestors, so scoping a query to a
51
- tier walks that chain.
52
- - **Channels** (\`normal\`, \`experimental\`, \`prerelease\`) gate visibility, so an
53
- in-progress block never leaks into a stable answer.
54
-
55
- ## Why RDF
56
-
57
- One graph makes every relationship first-class and queryable: \`block lookup\`
58
- follows edges to modifiers and subcomponents, \`graph query\` runs arbitrary
59
- SPARQL, and \`ontology show\` reads the schema itself. The store is built once
60
- by \`sources update\` and addressed by content hash, so the domain you query is
61
- exactly the domain that was published.`;
62
-
63
- export const blockPack: PackDefinition = {
64
- noun: "block",
65
- description: "Look up design system blocks.",
66
- colophon: DESIGN_SYSTEM_COLOPHON,
67
- lookup: {
68
- source: "graphql",
69
- toolDescription:
70
- 'Get detailed information about one or more design system blocks including anatomy, modifiers, and properties. Use when you need the full spec of specific blocks by name — detail: "summary" trims to the base view. Example: block_lookup { names: ["Button"] }.',
71
- by: "ds:name",
72
- types: ["ds:Component", "ds:Pattern", "ds:Layout", "ds:Subcomponent"],
73
- graphqlType: "UIBlock",
74
- fields: [
75
- { name: "tier", property: "ds:tier", label: "Tier" },
76
- {
77
- name: "figmaLink",
78
- property: "ds:figmaLink",
79
- label: "Figma",
80
- level: "detailed",
81
- },
82
- ],
83
- sections: [
84
- { name: "summary", property: "ds:summary", label: "Summary" },
85
- {
86
- name: "whenToUse",
87
- property: "ds:whenToUse",
88
- label: "When to use",
89
- level: "detailed",
90
- },
91
- {
92
- name: "whenNotToUse",
93
- property: "ds:whenNotToUse",
94
- label: "When not to use",
95
- level: "detailed",
96
- },
97
- {
98
- name: "guidelines",
99
- property: "ds:guidelines",
100
- label: "Guidelines",
101
- level: "detailed",
102
- },
103
- {
104
- name: "anatomyDsl",
105
- property: "ds:anatomyDsl",
106
- label: "Anatomy (DSL)",
107
- kind: "code",
108
- level: "detailed",
109
- },
110
- {
111
- name: "anatomyClassic",
112
- property: "ds:anatomyClassic",
113
- label: "Anatomy (classic)",
114
- kind: "code",
115
- level: "detailed",
116
- },
117
- ],
118
- expand: [
119
- {
120
- name: "modifierFamilies",
121
- heading: "Modifier Families",
122
- relation: "ds:hasModifierFamily",
123
- level: "detailed",
124
- select: [
125
- { name: "name", property: "ds:name" },
126
- {
127
- name: "values",
128
- relation: "ds:hasModifier",
129
- select: [{ name: "name", property: "ds:name" }],
130
- },
131
- ],
132
- },
133
- {
134
- name: "properties",
135
- heading: "Properties",
136
- relation: "ds:hasProperty",
137
- kind: "table",
138
- level: "detailed",
139
- select: [
140
- { name: "name", property: "ds:name" },
141
- { name: "type", property: "ds:propertyType" },
142
- { name: "optional", property: "ds:optional" },
143
- ],
144
- },
145
- {
146
- name: "subcomponents",
147
- heading: "Subcomponents",
148
- relation: "ds:hasSubcomponent",
149
- level: "detailed",
150
- select: [
151
- { name: "name", property: "ds:name" },
152
- { name: "uri", property: "ds:name", graphqlField: "uri" },
153
- ],
154
- },
155
- ],
156
- disclosure: {
157
- levels: ["summary", "standard", "detailed"],
158
- default: "detailed",
159
- },
160
- sample: {
161
- fixedCount: true,
162
- toolDescription:
163
- "Return randomly selected complete design-system blocks as exemplars. Use BEFORE writing queries to see actual data shapes, anatomy, and property names.",
164
- },
165
- },
166
- };
@@ -1,187 +0,0 @@
1
- /**
2
- * Block content-parity (PROTECTED) — on a FIXTURE graph, not the live one.
3
- *
4
- * The hand-written block lookup is gone; parity is asserted against the fixture
5
- * graph directly: Button and Modal resolve through the GraphQL `block lookup`
6
- * with the same content a direct SPARQL oracle returns (summary, guidance,
7
- * anatomy, tier, modifier families with values, properties, subcomponents). The
8
- * fixture DECLARES whenToUse/whenNotToUse (which the live graph superseded with
9
- * ds:usage), so those sections are exercised here. The hand-written `block list`
10
- * is checked for its tier/channel filtering and --all-tiers.
11
- */
12
-
13
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
14
- import type { LookupOutput } from "../../kernel/packs/resolveEntity.js";
15
- import { verbKey } from "../../kernel/packs/uniqueness.js";
16
- import type { PragmaRuntime } from "../../kernel/runtime/types.js";
17
- import type { VerbSpec } from "../../kernel/spec/types.js";
18
- import {
19
- BLOCK_PREFIXES,
20
- BLOCK_TTL,
21
- } from "../../testing/fixtures/blockGraph.js";
22
- import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
23
- import type { BlockRow } from "./blockList.verb.js";
24
- import { blockModule } from "./index.js";
25
-
26
- const DS = "https://ds.canonical.com/";
27
-
28
- const listVerb = blockModule.verbs.find(
29
- (v) => verbKey(v.path) === "block list",
30
- ) as VerbSpec;
31
- const lookupVerb = blockModule.verbs.find(
32
- (v) => verbKey(v.path) === "block lookup",
33
- ) as VerbSpec;
34
-
35
- let rt: PragmaRuntime;
36
-
37
- beforeAll(async () => {
38
- ({ rt } = await buildFixtureRuntime({
39
- ttl: BLOCK_TTL,
40
- prefixes: BLOCK_PREFIXES,
41
- detail: "detailed",
42
- }));
43
- });
44
-
45
- afterAll(async () => {
46
- (await rt.store.get()).store.dispose();
47
- });
48
-
49
- async function lookup(name: string): Promise<Record<string, unknown>> {
50
- const out = (await lookupVerb.run({ name: [name] }, rt)) as LookupOutput;
51
- expect(out.errors).toEqual([]);
52
- return out.results.at(0) as Record<string, unknown>;
53
- }
54
-
55
- /** Oracle: a single scalar from the graph, queried directly. */
56
- async function oracle(subject: string, predicate: string): Promise<string> {
57
- const result = await rt.query.sparql(
58
- `SELECT ?v WHERE { <${subject}> ${predicate} ?v }`,
59
- );
60
- return result.type === "select" ? (result.bindings[0]?.v ?? "") : "";
61
- }
62
-
63
- describe("block lookup — Button content parity (GraphQL, detailed)", () => {
64
- it("resolves the full Button spec with content matching the SPARQL oracle", async () => {
65
- const button = await lookup("Button");
66
- expect(button.uri).toBe(`${DS}button`);
67
- expect(button.name).toBe("Button");
68
- expect(button.tier).toBe(`${DS}global`);
69
-
70
- // Guidance + anatomy sections — each cross-checked against the graph.
71
- expect(button.summary).toBe(await oracle(`${DS}button`, "ds:summary"));
72
- expect(button.whenToUse).toBe(await oracle(`${DS}button`, "ds:whenToUse"));
73
- expect(button.whenNotToUse).toBe(
74
- await oracle(`${DS}button`, "ds:whenNotToUse"),
75
- );
76
- expect(button.guidelines).toBe(
77
- await oracle(`${DS}button`, "ds:guidelines"),
78
- );
79
- expect(button.anatomyDsl).toBe(
80
- await oracle(`${DS}button`, "ds:anatomyDsl"),
81
- );
82
- expect(button.figmaLink).toBe(await oracle(`${DS}button`, "ds:figmaLink"));
83
- });
84
-
85
- it("resolves the nested modifier families with values (inverse union)", async () => {
86
- const button = await lookup("Button");
87
- const families = button.modifierFamilies as {
88
- name: string;
89
- values?: string[];
90
- }[];
91
- expect(families.map((f) => f.name).sort()).toEqual([
92
- "density",
93
- "importance",
94
- ]);
95
- const importance = families.find((f) => f.name === "importance");
96
- expect(importance?.values?.sort()).toEqual(["primary", "secondary"]);
97
- });
98
-
99
- it("resolves properties and the subtype-scoped subcomponents identity field", async () => {
100
- const button = await lookup("Button");
101
- expect(button.properties).toEqual([
102
- { name: "disabled", type: "boolean", optional: "true" },
103
- ]);
104
- expect(button.subcomponents).toEqual([
105
- { name: "Button Icon", uri: `${DS}button.icon` },
106
- ]);
107
- });
108
-
109
- it("renders every declared section in the llm output", async () => {
110
- const out = (await lookupVerb.run(
111
- { name: ["Button"] },
112
- rt,
113
- )) as LookupOutput;
114
- const llm = lookupVerb.output.formatters.llm(out);
115
- expect(llm).toContain("## Button");
116
- expect(llm).toContain("### When to use");
117
- expect(llm).toContain("### Anatomy (DSL)");
118
- expect(llm).toContain("### Modifier Families");
119
- expect(llm).toContain("primary");
120
- });
121
- });
122
-
123
- describe("block lookup — Modal content parity (GraphQL, detailed)", () => {
124
- it("resolves the full Modal spec (a different block, same document engine)", async () => {
125
- const modal = await lookup("Modal");
126
- expect(modal.uri).toBe(`${DS}modal`);
127
- expect(modal.name).toBe("Modal");
128
- expect(modal.summary).toBe(await oracle(`${DS}modal`, "ds:summary"));
129
- expect(modal.whenToUse).toBe(await oracle(`${DS}modal`, "ds:whenToUse"));
130
- const families = modal.modifierFamilies as {
131
- name: string;
132
- values?: string[];
133
- }[];
134
- expect(families.map((f) => f.name)).toEqual(["size"]);
135
- expect(families[0]?.values?.sort()).toEqual(["large", "small"]);
136
- expect(modal.properties).toEqual([
137
- { name: "open", type: "boolean", optional: "false" },
138
- ]);
139
- // Modal has no subcomponents — the subtype-scoped selection is simply absent.
140
- expect(modal.subcomponents).toEqual([]);
141
- });
142
- });
143
-
144
- describe("block lookup — disclosure trims to the base view at summary", () => {
145
- it("summary keeps name/tier/summary and drops the detailed sections/expands", async () => {
146
- const out = (await lookupVerb.run(
147
- { name: ["Button"] },
148
- { ...rt, globalFlags: { ...rt.globalFlags, detail: "summary" } },
149
- )) as LookupOutput;
150
- const button = out.results.at(0) as Record<string, unknown>;
151
- expect(button.name).toBe("Button");
152
- expect(button.summary).toBeDefined();
153
- expect(button.whenToUse).toBeUndefined();
154
- expect(button.anatomyDsl).toBeUndefined();
155
- expect(button.modifierFamilies).toBeUndefined();
156
- expect(button.figmaLink).toBeUndefined();
157
- });
158
- });
159
-
160
- describe("block list — hand-written tier/channel filtering", () => {
161
- it("lists visible blocks with the summary row shape", async () => {
162
- const rows = (await listVerb.run({}, rt)) as BlockRow[];
163
- const byName = new Map(rows.map((r) => [r.name, r]));
164
- expect([...byName.keys()].sort()).toEqual(["Button", "Modal"]);
165
- const button = byName.get("Button");
166
- expect(button?.type).toBe("component");
167
- expect(button?.tier).toBe("global");
168
- expect(button?.uri).toBe(`${DS}button`);
169
- // GROUP_CONCAT of the family names (order-independent).
170
- expect(button?.modifiers.split(", ").sort()).toEqual([
171
- "density",
172
- "importance",
173
- ]);
174
- });
175
-
176
- it("--all-tiers also reveals the untiered subcomponent (A2)", async () => {
177
- // Button Icon is a ds:Subcomponent with NO ds:tier: the scoped/default view
178
- // omits it (a block joins the list through its tier), but --all-tiers must
179
- // surface every block, including untiered ones.
180
- const rows = (await listVerb.run({ allTiers: true }, rt)) as BlockRow[];
181
- expect(rows.map((r) => r.name).sort()).toEqual([
182
- "Button",
183
- "Button Icon",
184
- "Modal",
185
- ]);
186
- });
187
- });
@@ -1,78 +0,0 @@
1
- /**
2
- * Tier-chain inheritance + channel visibility for the hand-written `block list`.
3
- *
4
- * Ported from the v1 filters. Setting a tier activates a parent-chain filter
5
- * (`apps/lxd` → visible tiers `global`, `apps`, `apps/lxd`); the channel maps to
6
- * the set of visible release levels. Both are generated SPARQL clauses composed
7
- * only from validated pack terms — no user input reaches the query text (the
8
- * tier value comes from config, the channel from a closed enum).
9
- */
10
-
11
- import type { Channel } from "../../kernel/config/types.js";
12
-
13
- /** The `ds:` prefix — the store injects its PREFIX declaration. */
14
- const DS = "ds:";
15
-
16
- /** Release levels visible per channel setting. */
17
- export const CHANNEL_RELEASES: Record<Channel, readonly string[]> = {
18
- normal: ["stable"],
19
- experimental: ["stable", "experimental"],
20
- prerelease: ["stable", "experimental", "alpha", "beta"],
21
- };
22
-
23
- /**
24
- * The parent chain for a tier path.
25
- *
26
- * `apps/lxd` → `["global", "apps", "apps/lxd"]`; `undefined` → `[]` (all tiers).
27
- */
28
- export function resolveTierChain(tierPath: string | undefined): string[] {
29
- if (tierPath === undefined) return [];
30
- const normalized = tierPath.trim().toLowerCase();
31
- const chain: string[] = ["global"];
32
- const segments = normalized.split("/");
33
- for (let i = 0; i < segments.length; i++) {
34
- const path = segments.slice(0, i + 1).join("/");
35
- if (path !== "global") chain.push(path);
36
- }
37
- return chain;
38
- }
39
-
40
- /** A tier path's URI local name (slashes → underscores: `apps/lxd` → `apps_lxd`). */
41
- export function tierPathToLocal(tierPath: string): string {
42
- return tierPath.trim().toLowerCase().replace(/\//g, "_");
43
- }
44
-
45
- /**
46
- * A SPARQL FILTER clause for tier visibility, or empty when no tier is set.
47
- *
48
- * @param tierPath - The configured tier path (e.g. `apps/lxd`) or `undefined`.
49
- * @param varName - The SPARQL variable to filter (default `tier`).
50
- */
51
- export function buildTierFilter(
52
- tierPath: string | undefined,
53
- varName = "tier",
54
- ): string {
55
- if (tierPath === undefined) return "";
56
- const uriList = resolveTierChain(tierPath)
57
- .map((t) => `${DS}${tierPathToLocal(t)}`)
58
- .join(", ");
59
- return `FILTER(?${varName} IN (${uriList}))`;
60
- }
61
-
62
- /**
63
- * SPARQL clauses for channel visibility: bind `?release` if present, then filter
64
- * to allowed levels OR unbound (unannotated blocks are treated as stable).
65
- *
66
- * @param channel - The configured channel.
67
- * @param varName - The SPARQL variable to bind/filter (default `release`).
68
- */
69
- export function buildChannelFilter(
70
- channel: Channel,
71
- varName = "release",
72
- ): string {
73
- const uriList = CHANNEL_RELEASES[channel].map((r) => `${DS}${r}`).join(", ");
74
- return [
75
- `OPTIONAL { ?component ${DS}release ?${varName} }`,
76
- `FILTER(!BOUND(?${varName}) || ?${varName} IN (${uriList}))`,
77
- ].join("\n ");
78
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * The built-in pragma colophon — how the toolchain itself is made. Authored
3
- * Markdown grounded in this tree's real architecture; surfaced by `pragma
4
- * colophon` as the first section, before any active pack's domain colophon.
5
- *
6
- * `PRAGMA_COLOPHON` is the full narrative for humans; `PRAGMA_COLOPHON_SUMMARY`
7
- * is the condensed form `--format llm` emits (Markdown IS the agent-optimal shape).
8
- * Both are BODIES with no leading H1 — the renderer supplies the "pragma"
9
- * heading, so the section is never double-titled.
10
- */
11
-
12
- /** The full built-in colophon (Markdown body). */
13
- export const PRAGMA_COLOPHON = `pragma is a **domain-based toolchain**: one CLI and one MCP server projected
14
- from a single grammar, serving a knowledge-graph domain that reads as data.
15
-
16
- ## The effect monad
17
-
18
- Reads are plain \`async\` functions; a mutation instead *describes* its effects
19
- as a \`Task\` (\`@canonical/task\`) that is interpreted — under the real node
20
- interpreter, a \`--dry-run\` planner, or an \`--undo\` reverser. Describe-then-
21
- interpret means dry-run and undo come for free, and the dispatcher tells the two
22
- worlds apart on one bit: \`capability.mutates\`.
23
-
24
- ## One grammar, many projections
25
-
26
- Every capability is a \`VerbSpec\` — a noun, its params, its effect profile, its
27
- formatters. The CLI commands, the MCP tools, shell completion, and the
28
- surface/docs are all *projections* of that one shape, so they cannot drift. The
29
- projected surface is frozen in a covenant (\`surface/surface.v2.json\`): a single
30
- source of truth a test asserts the live grammar still emits, tool for tool.
31
-
32
- ## LLM-optimized output
33
-
34
- Each verb renders three ways — \`plain\` for a terminal, \`json\` for the machine
35
- envelope, and \`llm\` for condensed Markdown. \`--format llm\` (or a non-interactive
36
- stdout) selects the agent form: the same data, shaped for a model to read. This
37
- colophon is itself a showcase of that render model.
38
-
39
- ## Modular, storeless by construction
40
-
41
- Capabilities ship as **modules** — named bundles of verbs with optional
42
- boot / resource / prompt hooks. A verb declares whether it \`needsStore\`, and
43
- the dispatcher boots the triple store *only* for those; a storeless verb
44
- (\`info\`, \`config\`, \`capabilities\`, \`colophon\`) never pays for the graph.
45
-
46
- ## Scaffolding
47
-
48
- \`pragma create\` scaffolds components, packages, and applications through the
49
- \`@canonical/summon-*\` generators, reusing summon's rich Ink wizard when it runs
50
- interactively.
51
-
52
- ## The domain reads as data
53
-
54
- A domain is a **pack**: a declarative \`PackDefinition\` (its list / lookup
55
- queries) compiled into verbs, backed by a content-addressed graphpack that
56
- \`sources update\` builds once. Swap the pack and the same pragma serves a
57
- different domain — including the domain colophon printed below this one.`;
58
-
59
- /** The condensed colophon for `--format llm` (Markdown body, no leading H1). */
60
- export const PRAGMA_COLOPHON_SUMMARY = `pragma is a domain-based toolchain: one CLI + MCP server projected from a single \`VerbSpec\` grammar.
61
-
62
- - **Effect monad** (\`@canonical/task\`): reads are async; a mutation returns an interpreted \`Task\`, so \`--dry-run\` and \`--undo\` are free. The dispatcher branches on \`capability.mutates\`.
63
- - **One grammar, many projections**: CLI, MCP tools, completion, and docs all project one \`VerbSpec\`; the emitted surface is frozen in a covenant so the projections never drift.
64
- - **LLM-optimized output**: every verb renders \`plain\` / \`json\` / \`llm\`; \`--format llm\` (or a piped stdout) emits condensed Markdown for agents.
65
- - **Modular + storeless**: capability modules; the triple store boots only for \`needsStore\` verbs.
66
- - **Domain as data**: a pack is a declarative \`PackDefinition\` compiled to verbs over a content-addressed graph built by \`sources update\`.`;
@@ -1,15 +0,0 @@
1
- /**
2
- * The `modifier` capability module — the bundled pack (SPARQL list, GraphQL
3
- * lookup) compiled to verbs.
4
- */
5
-
6
- import { compilePack } from "../../kernel/packs/compile.js";
7
- import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
8
- import type { CapabilityModule } from "../../kernel/spec/types.js";
9
- import { modifierPack } from "./pack.js";
10
-
11
- /** The `modifier` capability module (`list`, `lookup`). */
12
- export const modifierModule: CapabilityModule = {
13
- name: "modifier",
14
- verbs: compilePack(modifierPack, "bundled:modifier", DEFAULT_PREFIX_MAP),
15
- };
@@ -1,64 +0,0 @@
1
- /**
2
- * The bundled `modifier` pack — modifier families as data.
3
- *
4
- * `modifier list` is SPARQL (an alternation path collects values asserted in
5
- * either direction); `modifier lookup` is GRAPHQL, where the compiled
6
- * `ModifierFamily.modifiers` field is the declared-inverse union and resolves
7
- * both directions in ONE generated document — exactly the case the GraphQL fetch
8
- * path exists for.
9
- */
10
-
11
- import type { PackDefinition } from "../../kernel/packs/types.js";
12
-
13
- export const modifierPack: PackDefinition = {
14
- noun: "modifier",
15
- description: "List all modifier families.",
16
- toolDescription:
17
- "List all modifier families with their values. Use when browsing which modifier families exist and the values each allows. Example: modifier_list {}.",
18
- list: {
19
- query: [
20
- "SELECT ?uri ?name",
21
- ' (GROUP_CONCAT(DISTINCT ?valueName; separator=", ") AS ?values)',
22
- "WHERE {",
23
- " ?uri a ds:ModifierFamily ;",
24
- " ds:name ?name .",
25
- " OPTIONAL {",
26
- " ?uri (ds:hasModifier|^ds:modifierFamily) ?value .",
27
- " ?value ds:name ?valueName .",
28
- " }",
29
- "}",
30
- "GROUP BY ?uri ?name",
31
- "ORDER BY ?name",
32
- ].join("\n"),
33
- columns: [
34
- { field: "uri", label: "IRI" },
35
- { field: "name", label: "Name" },
36
- { field: "values", label: "Values" },
37
- ],
38
- emptyRecovery: {
39
- message:
40
- "No modifier families in the store. Build it from the configured design-system packages.",
41
- cli: "pragma sources update",
42
- },
43
- },
44
- lookup: {
45
- source: "graphql",
46
- by: "ds:name",
47
- type: "ds:ModifierFamily",
48
- toolDescription:
49
- 'Get values and usage details for one or more modifier families by name. Use when you need the allowed values of specific families. Example: modifier_lookup { names: ["importance"] }.',
50
- expand: [
51
- {
52
- name: "values",
53
- heading: "Values",
54
- relation: "ds:hasModifier",
55
- select: [{ name: "name", property: "ds:name" }],
56
- },
57
- ],
58
- sample: {
59
- fixedCount: true,
60
- toolDescription:
61
- "Return randomly selected complete modifier families (with value lists) as exemplars. Use BEFORE writing queries to see actual data shapes.",
62
- },
63
- },
64
- };
@@ -1,18 +0,0 @@
1
- /**
2
- * The `standard` capability module — the bundled pack compiled to verbs.
3
- *
4
- * Compiled at import (fast-path safe: compilePack is pure/zod-free) so the module
5
- * is surface-deterministic. A config/package story for `standard` overrides it at
6
- * dispatch (see kernel/packs/collect).
7
- */
8
-
9
- import { compilePack } from "../../kernel/packs/compile.js";
10
- import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
11
- import type { CapabilityModule } from "../../kernel/spec/types.js";
12
- import { standardPack } from "./pack.js";
13
-
14
- /** The `standard` capability module (list, categories, lookup, sample). */
15
- export const standardModule: CapabilityModule = {
16
- name: "standard",
17
- verbs: compilePack(standardPack, "bundled:standard", DEFAULT_PREFIX_MAP),
18
- };