@canonical/pragma-cli 0.35.0 → 0.36.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 +2 -2
- package/bundled-skills/add-standard/SKILL.md +338 -0
- package/bundled-skills/adoption-a1-styles/SKILL.md +269 -0
- package/bundled-skills/adoption-a2-components/SKILL.md +291 -0
- package/bundled-skills/adoption-a3-forms/SKILL.md +260 -0
- package/bundled-skills/anatomy-author/ANATOMY_DSL_SPEC.md +406 -0
- package/bundled-skills/anatomy-author/SKILL.md +1226 -0
- package/bundled-skills/design-auditor/SKILL.md +455 -0
- package/bundled-skills/implement-component/SKILL.md +333 -0
- package/bundled-skills/specify-component/SKILL.md +331 -0
- package/bundled-skills/specify-pattern/SKILL.md +292 -0
- package/dist/package.json +16 -15
- package/dist/pragma.conf.js +236 -34
- package/dist/pragma.conf.js.map +1 -1
- package/dist/src/bin.js +1 -1
- package/dist/src/bin.js.map +1 -1
- package/dist/src/capabilities/colophon/colophon.render.js +1 -1
- package/dist/src/capabilities/colophon/colophon.render.js.map +1 -1
- package/dist/src/capabilities/create/mount.js +4 -3
- package/dist/src/capabilities/create/mount.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +60 -4
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkShellCompletions.js +8 -8
- package/dist/src/capabilities/doctor/checks/checkShellCompletions.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/harnessInventory.js +195 -0
- package/dist/src/capabilities/doctor/checks/harnessInventory.js.map +1 -0
- package/dist/src/capabilities/doctor/checks/index.js +6 -6
- package/dist/src/capabilities/doctor/checks/targetHealth.js +194 -50
- package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
- package/dist/src/capabilities/doctor/doctor.render.js +43 -64
- package/dist/src/capabilities/doctor/doctor.render.js.map +1 -1
- package/dist/src/capabilities/doctor/doctor.verb.js +6 -2
- package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
- package/dist/src/capabilities/doctor/runChecks.js +14 -11
- package/dist/src/capabilities/doctor/runChecks.js.map +1 -1
- package/dist/src/capabilities/graph/query.render.js +2 -2
- package/dist/src/capabilities/graph/query.render.js.map +1 -1
- package/dist/src/capabilities/info/collectInfo.js +8 -2
- package/dist/src/capabilities/info/collectInfo.js.map +1 -1
- package/dist/src/capabilities/info/info.render.js +6 -2
- package/dist/src/capabilities/info/info.render.js.map +1 -1
- package/dist/src/capabilities/prompt/prompt.render.js +2 -2
- package/dist/src/capabilities/prompt/prompt.render.js.map +1 -1
- package/dist/src/capabilities/setup/buildPlan.js +43 -39
- package/dist/src/capabilities/setup/buildPlan.js.map +1 -1
- package/dist/src/capabilities/setup/mode.js +2 -2
- package/dist/src/capabilities/setup/operations/index.js +4 -4
- package/dist/src/capabilities/setup/operations/index.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupGenerator.js +92 -45
- package/dist/src/capabilities/setup/operations/setupGenerator.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupLsp.js +88 -36
- package/dist/src/capabilities/setup/operations/setupLsp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupMcp.js +97 -51
- package/dist/src/capabilities/setup/operations/setupMcp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupSkills.js +325 -47
- package/dist/src/capabilities/setup/operations/setupSkills.js.map +1 -1
- package/dist/src/capabilities/setup/plan.js.map +1 -1
- package/dist/src/capabilities/setup/plan.render.js +144 -66
- package/dist/src/capabilities/setup/plan.render.js.map +1 -1
- package/dist/src/capabilities/setup/setup.render.js +1 -1
- package/dist/src/capabilities/setup/setup.verb.js +86 -33
- package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
- package/dist/src/capabilities/setup/targets.js +110 -45
- package/dist/src/capabilities/setup/targets.js.map +1 -1
- package/dist/src/capabilities/shared/index.js +6 -5
- package/dist/src/capabilities/shared/index.js.map +1 -1
- package/dist/src/capabilities/shared/packageManager.js +300 -54
- package/dist/src/capabilities/shared/packageManager.js.map +1 -1
- package/dist/src/capabilities/skill/discover.js +97 -11
- package/dist/src/capabilities/skill/discover.js.map +1 -1
- package/dist/src/capabilities/skill/render.js +2 -2
- package/dist/src/capabilities/skill/render.js.map +1 -1
- package/dist/src/capabilities/sources/installSkills.js +145 -3
- package/dist/src/capabilities/sources/installSkills.js.map +1 -1
- package/dist/src/capabilities/sources/runUpdate.js +68 -2
- package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
- package/dist/src/capabilities/sources/update.verb.js +3 -3
- package/dist/src/capabilities/sources/update.verb.js.map +1 -1
- package/dist/src/capabilities/upgrade/runUpgrade.js +43 -7
- package/dist/src/capabilities/upgrade/runUpgrade.js.map +1 -1
- package/dist/src/capabilities/upgrade/upgrade.render.js +10 -2
- package/dist/src/capabilities/upgrade/upgrade.render.js.map +1 -1
- package/dist/src/constants.js +6 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/index.js +11 -2
- package/dist/src/kernel/index.js.map +1 -1
- package/dist/src/kernel/interactivity.js +68 -0
- package/dist/src/kernel/interactivity.js.map +1 -0
- package/dist/src/kernel/packs/renderPack.js +3 -3
- package/dist/src/kernel/packs/renderPack.js.map +1 -1
- package/dist/src/kernel/packs/resolveEntity.js +63 -12
- package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
- package/dist/src/kernel/packs/runBodies.js +57 -4
- package/dist/src/kernel/packs/runBodies.js.map +1 -1
- package/dist/src/kernel/packs/schema.js +54 -2
- package/dist/src/kernel/packs/schema.js.map +1 -1
- package/dist/src/kernel/packs/sparql/applyFilters.js +104 -5
- package/dist/src/kernel/packs/sparql/applyFilters.js.map +1 -1
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js +306 -43
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
- package/dist/src/kernel/packs/types.js.map +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
- package/dist/src/kernel/project/cli/dispatch.js +23 -23
- package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
- package/dist/src/kernel/project/cli/globalFlags.js +4 -1
- package/dist/src/kernel/project/cli/globalFlags.js.map +1 -1
- package/dist/src/kernel/project/cli/helpFormat.js +1 -2
- package/dist/src/kernel/project/cli/helpFormat.js.map +1 -1
- package/dist/src/kernel/project/cli/rootHelp.js +34 -4
- package/dist/src/kernel/project/cli/rootHelp.js.map +1 -1
- package/dist/src/kernel/project/mcp/registerVerb.js +16 -1
- package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
- package/dist/src/kernel/render/renderers.js +1 -1
- package/dist/src/kernel/render/style.js +29 -9
- package/dist/src/kernel/render/style.js.map +1 -1
- package/dist/src/kernel/render/vocabulary.js +174 -0
- package/dist/src/kernel/render/vocabulary.js.map +1 -0
- package/dist/src/kernel/spec/emitReference.js +1 -1
- package/dist/src/kernel/spec/emitReference.js.map +1 -1
- package/package.json +16 -15
- package/pragma.conf.ts +241 -34
- package/src/bin.ts +8 -1
- package/src/capabilities/block.parity.test.ts +25 -11
- package/src/capabilities/block.shipped.exec.test.ts +282 -0
- package/src/capabilities/block.tierRank.exec.test.ts +300 -0
- package/src/capabilities/colophon/colophon.render.ts +1 -2
- package/src/capabilities/colophon/colophon.test.ts +2 -2
- package/src/capabilities/create/createGrammar.test.ts +1 -1
- package/src/capabilities/create/mount.ts +3 -3
- package/src/capabilities/distribution.parity.test.ts +4 -0
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +69 -4
- package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +6 -4
- package/src/capabilities/doctor/checks/checkShellCompletions.ts +8 -8
- package/src/capabilities/doctor/checks/harnessInventory.test.ts +219 -0
- package/src/capabilities/doctor/checks/harnessInventory.ts +298 -0
- package/src/capabilities/doctor/checks/index.ts +6 -6
- package/src/capabilities/doctor/checks/targetHealth.ts +229 -59
- package/src/capabilities/doctor/doctor.render.test.ts +108 -32
- package/src/capabilities/doctor/doctor.render.ts +56 -80
- package/src/capabilities/doctor/doctor.test.ts +247 -35
- package/src/capabilities/doctor/doctor.verb.ts +7 -2
- package/src/capabilities/doctor/runChecks.ts +14 -11
- package/src/capabilities/doctor/types.ts +15 -24
- package/src/capabilities/emptyRecovery.test.ts +10 -2
- package/src/capabilities/graph/query.render.ts +2 -2
- package/src/capabilities/info/collectInfo.ts +8 -1
- package/src/capabilities/info/info.render.ts +6 -2
- package/src/capabilities/info/info.test.ts +37 -1
- package/src/capabilities/info/types.ts +10 -2
- package/src/capabilities/prompt/prompt.render.ts +2 -2
- package/src/capabilities/renderVocabularySync.test.ts +82 -0
- package/src/capabilities/scopeTypeSync.test.ts +29 -15
- package/src/capabilities/setup/buildPlan.ts +45 -41
- package/src/capabilities/setup/index.ts +1 -1
- package/src/capabilities/setup/mode.ts +2 -2
- package/src/capabilities/setup/operations/index.ts +6 -1
- package/src/capabilities/setup/operations/setupGenerator.ts +144 -70
- package/src/capabilities/setup/operations/setupLsp.ts +129 -37
- package/src/capabilities/setup/operations/setupMcp.ts +132 -61
- package/src/capabilities/setup/operations/setupSkills.ts +392 -58
- package/src/capabilities/setup/plan.render.ts +171 -76
- package/src/capabilities/setup/plan.ts +17 -12
- package/src/capabilities/setup/setup.mcp.correctness.test.ts +9 -9
- package/src/capabilities/setup/setup.render.test.ts +50 -36
- package/src/capabilities/setup/setup.render.ts +1 -1
- package/src/capabilities/setup/setup.test.ts +881 -50
- package/src/capabilities/setup/setup.verb.ts +91 -33
- package/src/capabilities/setup/targets.ts +120 -52
- package/src/capabilities/setup/types.ts +10 -18
- package/src/capabilities/shared/index.ts +17 -6
- package/src/capabilities/shared/packageManager.test.ts +421 -6
- package/src/capabilities/shared/packageManager.ts +394 -59
- package/src/capabilities/skill/bundledSkills.test.ts +347 -0
- package/src/capabilities/skill/discover.ts +100 -11
- package/src/capabilities/skill/render.ts +2 -2
- package/src/capabilities/skill/skill.test.ts +17 -4
- package/src/capabilities/sources/installSkills.ts +181 -3
- package/src/capabilities/sources/runUpdate.ts +78 -2
- package/src/capabilities/sources/sources.test.ts +228 -0
- package/src/capabilities/sources/update.verb.ts +3 -3
- package/src/capabilities/surface.test.ts +2 -2
- package/src/capabilities/upgrade/runUpgrade.ts +45 -6
- package/src/capabilities/upgrade/types.ts +10 -2
- package/src/capabilities/upgrade/upgrade.render.ts +9 -2
- package/src/capabilities/upgrade/upgrade.test.ts +72 -0
- package/src/constants.ts +6 -1
- package/src/identity.test.ts +18 -5
- package/src/kernel/completion/entitySource.test.ts +15 -2
- package/src/kernel/completion/safety.test.ts +16 -9
- package/src/kernel/config/defaults.test.ts +2 -1
- package/src/kernel/index.ts +11 -2
- package/src/kernel/interactivity.test.ts +76 -0
- package/src/kernel/interactivity.ts +69 -0
- package/src/kernel/packs/compile.test.ts +92 -0
- package/src/kernel/packs/renderPack.ts +3 -3
- package/src/kernel/packs/resolveEntity.test.ts +75 -14
- package/src/kernel/packs/resolveEntity.ts +88 -24
- package/src/kernel/packs/runBodies.ts +84 -19
- package/src/kernel/packs/schema.ts +60 -4
- package/src/kernel/packs/sparql/applyFilters.ts +125 -4
- package/src/kernel/packs/sparql/buildLookupQuery.test.ts +290 -0
- package/src/kernel/packs/sparql/buildLookupQuery.ts +323 -45
- package/src/kernel/packs/toolDescription.test.ts +35 -1
- package/src/kernel/packs/types.ts +125 -2
- package/src/kernel/project/cli/buildProgram.test.ts +73 -2
- package/src/kernel/project/cli/buildProgram.ts +8 -1
- package/src/kernel/project/cli/dispatch.test.ts +5 -4
- package/src/kernel/project/cli/dispatch.ts +25 -24
- package/src/kernel/project/cli/globalFlags.ts +4 -1
- package/src/kernel/project/cli/helpFormat.ts +1 -2
- package/src/kernel/project/cli/rootHelp.ts +36 -3
- package/src/kernel/project/mcp/registerVerb.ts +20 -1
- package/src/kernel/render/renderers.ts +1 -1
- package/src/kernel/render/style.ts +32 -9
- package/src/kernel/render/vocabulary.ts +276 -0
- package/src/kernel/spec/emitReference.ts +1 -1
- package/src/kernel/spec/types.ts +35 -6
- package/src/testing/PARITY_GAPS.ts +9 -3
- package/src/testing/behavioral/docExamples.test.ts +4 -2
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +110 -7
- package/src/testing/behavioral/journeys.firstInstall.test.ts +7 -2
- package/src/testing/behavioral/journeys.packageStories.test.ts +6 -3
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +26 -1
- package/src/testing/eval/cases/readNouns.ts +245 -9
- package/src/testing/fixtures/blockGraph.ts +28 -13
- package/src/testing/fixtures/graph/canonical.ts +95 -12
- package/dist/src/capabilities/shared/bands.js +0 -16
- package/dist/src/capabilities/shared/bands.js.map +0 -1
- package/src/capabilities/shared/bands.ts +0 -16
package/pragma.conf.ts
CHANGED
|
@@ -97,8 +97,30 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
97
97
|
// Base level mirrors the old summary view (name/tier/summary); the default is
|
|
98
98
|
// `detailed`, matching the old CLI which rendered anatomy and modifiers
|
|
99
99
|
// without a flag. A derived name that maps onto no schema field is omitted
|
|
100
|
-
// (OPTIONAL parity), so a graph
|
|
101
|
-
// gracefully.
|
|
100
|
+
// (OPTIONAL parity), so a graph missing one of these properties degrades
|
|
101
|
+
// gracefully rather than erroring.
|
|
102
|
+
//
|
|
103
|
+
// That graceful degradation is also how this story went silent: it used to
|
|
104
|
+
// read `ds:whenToUse`/`ds:whenNotToUse`, which the ontology RETIRED in favour
|
|
105
|
+
// of a single `ds:usage` — "Subsumes the former whenToUse/whenNotToUse" is
|
|
106
|
+
// that property's own skos:definition. The shipped pack asserts `ds:usage` on
|
|
107
|
+
// all 264 blocks and neither retired term on any of them, so every
|
|
108
|
+
// `block lookup` on every install rendered no usage narrative at all —
|
|
109
|
+
// silently, because a name that maps onto no schema field is exactly the case
|
|
110
|
+
// OPTIONAL parity swallows. The retired terms are NOT kept as a fallback:
|
|
111
|
+
// `ds:usage` subsumes them, so a pack carrying both would print the same
|
|
112
|
+
// guidance twice, and a declaration no shipped graph can satisfy is
|
|
113
|
+
// untestable by construction — which is what let the silence ship.
|
|
114
|
+
// `block.shipped.exec.test.ts` now holds every graph term declared here — the
|
|
115
|
+
// identity property, fields, sections, expand relations, and every term
|
|
116
|
+
// selected beneath them, walked recursively — to being DEFINED as a property
|
|
117
|
+
// by the SHIPPED ontology. Defined, not asserted, and the difference is the
|
|
118
|
+
// whole point: a term the ontology never defines is a story bug that can
|
|
119
|
+
// never render, on any block, on any install — this defect. A term it defines
|
|
120
|
+
// that no instance asserts yet (`ds:figmaLink` today) is a content gap
|
|
121
|
+
// upstream, which the OPTIONAL parity above degrades over gracefully and
|
|
122
|
+
// which this pack has no business failing on. `ds:usage` alone is ALSO held
|
|
123
|
+
// to being asserted, on every block, because its absence is what shipped.
|
|
102
124
|
//
|
|
103
125
|
// Disclosure declares the FULL canonical ladder `[summary, standard,
|
|
104
126
|
// detailed]` — the same set `standard` declares — so a config
|
|
@@ -121,14 +143,33 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
121
143
|
" VALUES ?class { ds:Component ds:Pattern ds:Layout ds:Subcomponent }",
|
|
122
144
|
" ?uri a ?class .",
|
|
123
145
|
" OPTIONAL { ?uri ds:name ?dsName }",
|
|
124
|
-
" OPTIONAL { ?uri ds:tier ?tierUri }",
|
|
146
|
+
" OPTIONAL { ?uri ds:tier ?tierUri . OPTIONAL { ?tierUri ds:name ?tierName } }",
|
|
125
147
|
" OPTIONAL { ?uri ds:hasModifierFamily ?family . ?family ds:name ?modName }",
|
|
126
148
|
' BIND(COALESCE(?dsName, REPLACE(STR(?uri), "^.*[/#]", "")) AS ?name)',
|
|
127
149
|
' BIND(LCASE(REPLACE(STR(?class), "^.*[/#]", "")) AS ?type)',
|
|
128
150
|
' BIND(REPLACE(STR(?tierUri), "^.*[/#]", "") AS ?tier)',
|
|
151
|
+
// `ORDER BY ?name` alone is not a total order, and 25 names here are
|
|
152
|
+
// shared by two or three blocks. SPARQL says nothing about tied rows,
|
|
153
|
+
// so the store's scan decided: ONE run gave `Button` launchpad-first
|
|
154
|
+
// and `CheckboxInput` global-first. Tier depth, then `STR(?uri)`,
|
|
155
|
+
// makes it total — the shallower tier leads its name group, and equal
|
|
156
|
+
// depths fall back to a key that cannot tie.
|
|
157
|
+
//
|
|
158
|
+
// The depth is the same one `lookup` ranks by, spelled out because a
|
|
159
|
+
// list query is declared TEXT the kernel does not compose. Only the
|
|
160
|
+
// depth: a browse ordered by NAME is not the place to re-litigate which
|
|
161
|
+
// block the name MEANS (that is `lookup`'s ranking, which also weighs
|
|
162
|
+
// the block's type), and every row here already prints its own type.
|
|
163
|
+
//
|
|
164
|
+
// The depth-0 IF is the store's, not style: oxigraph raises on
|
|
165
|
+
// `0.2 * 0`, and a raising BIND leaves `?tierRank` unbound — which is
|
|
166
|
+
// exactly how a top-tier block silently sorted last (see
|
|
167
|
+
// `sparqlProduct` in kernel/packs/sparql/buildLookupQuery.ts).
|
|
168
|
+
' BIND(STRLEN(?tierName) - STRLEN(REPLACE(?tierName, "/", "")) AS ?tierDepth)',
|
|
169
|
+
" BIND(COALESCE(IF(?tierDepth = 0, 1, 1 - (0.2 * ?tierDepth)), 0) AS ?tierRank)",
|
|
129
170
|
"}",
|
|
130
|
-
"GROUP BY ?uri ?name ?type ?tier",
|
|
131
|
-
"ORDER BY ?name",
|
|
171
|
+
"GROUP BY ?uri ?name ?type ?tier ?tierRank",
|
|
172
|
+
"ORDER BY ?name DESC(?tierRank) STR(?uri)",
|
|
132
173
|
].join("\n"),
|
|
133
174
|
columns: [
|
|
134
175
|
{ field: "name", label: "Name" },
|
|
@@ -153,9 +194,41 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
153
194
|
// for the query "button" the 86 `…-close_button` subcomponents used to
|
|
154
195
|
// outrank `ds:global.component.button` on the alphabet alone. Weighting
|
|
155
196
|
// them below 1 sinks every one of them under every component at equal
|
|
156
|
-
// match score,
|
|
157
|
-
// listing
|
|
197
|
+
// match score, lowers their `annotations.priority` in the resource
|
|
198
|
+
// listing, and — since a name resolve now RANKS rather than picks — sorts
|
|
199
|
+
// them under every component a shared name also reaches.
|
|
158
200
|
weights: { "ds:Subcomponent": 0.6 },
|
|
201
|
+
// The other half of that judgement, and the reason it is a PRODUCT and
|
|
202
|
+
// not a tiebreak. 25 live block names are shared by two or three blocks
|
|
203
|
+
// across tiers, and `weights` alone cannot separate two components; the
|
|
204
|
+
// alphabet decided, so `Button` answered with Launchpad's and never
|
|
205
|
+
// mentioned the global one. A tier's DEPTH is what ranks it: `Global` is
|
|
206
|
+
// depth 1 and worth 1, `Apps/Launchpad` is depth 2 and worth 0.8, so
|
|
207
|
+
//
|
|
208
|
+
// Button global component 1 × 1 > launchpad component 1 × 0.8
|
|
209
|
+
// TextInput global SUBcomponent 0.6 × 1 < launchpad component 1 × 0.8
|
|
210
|
+
//
|
|
211
|
+
// — the global block wins where both are whole blocks, and the editorial
|
|
212
|
+
// rule that a whole component beats a part survives the addition. A pure
|
|
213
|
+
// tier tiebreak would have inverted the second case.
|
|
214
|
+
//
|
|
215
|
+
// DERIVED, never enumerated: the depth is the `/` count in the tier's
|
|
216
|
+
// OWN `ds:name` (`"Apps/Launchpad"`), not in its IRI (`ds:apps_launchpad`
|
|
217
|
+
// — the slash exists only in the name), so a tier added upstream tomorrow
|
|
218
|
+
// is ranked correctly without editing anything here.
|
|
219
|
+
//
|
|
220
|
+
// Declared as DATA beside `weights` for the same reason `weights` is:
|
|
221
|
+
// editorial judgement the ontology has not yet made belongs in the config
|
|
222
|
+
// layer, which "wins every harvest" when upstream is silent. `asserted`
|
|
223
|
+
// is the exit: the day `ds:tierRank` is asserted upstream it takes
|
|
224
|
+
// precedence over the derived depth (`COALESCE`), and this whole entry is
|
|
225
|
+
// deleted with no code change.
|
|
226
|
+
scopeWeight: {
|
|
227
|
+
via: "ds:tier",
|
|
228
|
+
by: "ds:name",
|
|
229
|
+
falloff: 0.2,
|
|
230
|
+
asserted: "ds:tierRank",
|
|
231
|
+
},
|
|
159
232
|
graphqlType: "UIBlock",
|
|
160
233
|
fields: [
|
|
161
234
|
{ name: "tier", property: "ds:tier", label: "Tier" },
|
|
@@ -168,16 +241,19 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
168
241
|
],
|
|
169
242
|
sections: [
|
|
170
243
|
{ name: "summary", property: "ds:summary", label: "Summary" },
|
|
244
|
+
// ONE section, because `ds:usage` is ONE property: its literal is
|
|
245
|
+
// free-text Markdown carrying its own `### When to use` / `### When not
|
|
246
|
+
// to use` sub-sections (78 and 71 of the 126 non-empty ones do), so
|
|
247
|
+
// splitting it back into two headings here would mean parsing prose the
|
|
248
|
+
// graph deliberately keeps whole. The renderer demotes a body's own ATX
|
|
249
|
+
// headings below the section heading, so those sub-sections nest UNDER
|
|
250
|
+
// `### Usage` instead of colliding with it. Half the blocks assert an
|
|
251
|
+
// EMPTY `ds:usage` (138 of 264); the renderer skips empty sections, so
|
|
252
|
+
// those print no heading rather than an empty one.
|
|
171
253
|
{
|
|
172
|
-
name: "
|
|
173
|
-
property: "ds:
|
|
174
|
-
label: "
|
|
175
|
-
level: "detailed",
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: "whenNotToUse",
|
|
179
|
-
property: "ds:whenNotToUse",
|
|
180
|
-
label: "When not to use",
|
|
254
|
+
name: "usage",
|
|
255
|
+
property: "ds:usage",
|
|
256
|
+
label: "Usage",
|
|
181
257
|
level: "detailed",
|
|
182
258
|
},
|
|
183
259
|
{
|
|
@@ -246,7 +322,7 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
246
322
|
sample: {
|
|
247
323
|
fixedCount: true,
|
|
248
324
|
toolDescription:
|
|
249
|
-
"Return randomly selected complete design-system blocks as exemplars. Use BEFORE writing queries to see actual data shapes, anatomy, and property names.",
|
|
325
|
+
"Return randomly selected complete design-system blocks as exemplars. Use BEFORE writing queries to see actual data shapes, anatomy, and property names. Example: block_sample {}.",
|
|
250
326
|
},
|
|
251
327
|
},
|
|
252
328
|
},
|
|
@@ -303,7 +379,7 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
303
379
|
sample: {
|
|
304
380
|
fixedCount: true,
|
|
305
381
|
toolDescription:
|
|
306
|
-
"Return randomly selected complete design tokens (with theme values) as exemplars. Use BEFORE writing queries to see actual data shapes.",
|
|
382
|
+
"Return randomly selected complete design tokens (with theme values) as exemplars. Use BEFORE writing queries to see actual data shapes. Example: token_sample {}.",
|
|
307
383
|
},
|
|
308
384
|
},
|
|
309
385
|
},
|
|
@@ -361,7 +437,7 @@ const designSystemStories: readonly PackDefinition[] = [
|
|
|
361
437
|
sample: {
|
|
362
438
|
fixedCount: true,
|
|
363
439
|
toolDescription:
|
|
364
|
-
"Return randomly selected complete modifier families (with value lists) as exemplars. Use BEFORE writing queries to see actual data shapes.",
|
|
440
|
+
"Return randomly selected complete modifier families (with value lists) as exemplars. Use BEFORE writing queries to see actual data shapes. Example: modifier_sample {}.",
|
|
365
441
|
},
|
|
366
442
|
},
|
|
367
443
|
},
|
|
@@ -421,7 +497,7 @@ const conceptStory: PackDefinition = {
|
|
|
421
497
|
noun: "concept",
|
|
422
498
|
description: "List design-system concepts.",
|
|
423
499
|
toolDescription:
|
|
424
|
-
|
|
500
|
+
'List design-system concepts — long-form foundations, how-to guides, and decision guides not bound to a single UI block. Optionally filter by type or search. Example: concept_list { type: "Explanation" }.',
|
|
425
501
|
list: {
|
|
426
502
|
query: [
|
|
427
503
|
"SELECT ?uri ?name ?type ?summary",
|
|
@@ -443,6 +519,20 @@ const conceptStory: PackDefinition = {
|
|
|
443
519
|
{
|
|
444
520
|
param: "type",
|
|
445
521
|
variable: "type",
|
|
522
|
+
// `ds:ConceptType` is the vocabulary; the concepts are the population.
|
|
523
|
+
// The shipped graph declares six types and uses two, so validating
|
|
524
|
+
// against the rows rejected "Decision guide" — a type the ontology
|
|
525
|
+
// declares — as an invalid argument instead of answering with the
|
|
526
|
+
// empty list it actually has.
|
|
527
|
+
vocabulary: {
|
|
528
|
+
query: [
|
|
529
|
+
"SELECT DISTINCT ?name WHERE {",
|
|
530
|
+
" ?conceptType a ds:ConceptType ;",
|
|
531
|
+
" ds:name ?name .",
|
|
532
|
+
"}",
|
|
533
|
+
].join("\n"),
|
|
534
|
+
variable: "name",
|
|
535
|
+
},
|
|
446
536
|
description: "Filter by concept type (e.g. Explanation, How-to guide).",
|
|
447
537
|
},
|
|
448
538
|
],
|
|
@@ -463,7 +553,7 @@ const conceptStory: PackDefinition = {
|
|
|
463
553
|
description:
|
|
464
554
|
"Look up a concept's full documentation by name, IRI, or glob.",
|
|
465
555
|
toolDescription:
|
|
466
|
-
|
|
556
|
+
'Get a design-system concept\'s full Markdown documentation. Address concepts by the name concept_list publishes, by prefixed name (ds:concept.…), by absolute IRI, or by a glob. Example: concept_lookup { name: ["Foundations: Grid"] }.',
|
|
467
557
|
fields: [
|
|
468
558
|
{ name: "type", property: "ds:conceptType/ds:name", label: "Type" },
|
|
469
559
|
{ name: "tier", property: "ds:tier", label: "Tier" },
|
|
@@ -544,14 +634,34 @@ const implementationStory: PackDefinition = {
|
|
|
544
634
|
{ field: "uri", label: "IRI" },
|
|
545
635
|
],
|
|
546
636
|
filters: [
|
|
637
|
+
// Both vocabularies are read off `ds:ImplementationLibrary`, the subject
|
|
638
|
+
// that carries them — the same terms `implementation libraries`
|
|
639
|
+
// enumerates. A library that implements nothing yet still exists, and
|
|
640
|
+
// asking for it is an empty answer rather than a bad argument.
|
|
547
641
|
{
|
|
548
642
|
param: "platform",
|
|
549
643
|
variable: "platform",
|
|
644
|
+
vocabulary: {
|
|
645
|
+
query: [
|
|
646
|
+
"SELECT DISTINCT ?platform WHERE {",
|
|
647
|
+
" ?lib a ds:ImplementationLibrary ;",
|
|
648
|
+
" ds:platform ?platform .",
|
|
649
|
+
"}",
|
|
650
|
+
].join("\n"),
|
|
651
|
+
},
|
|
550
652
|
description: "Filter by platform (e.g. react, svelte, typescript).",
|
|
551
653
|
},
|
|
552
654
|
{
|
|
553
655
|
param: "library",
|
|
554
656
|
variable: "library",
|
|
657
|
+
vocabulary: {
|
|
658
|
+
query: [
|
|
659
|
+
"SELECT DISTINCT ?library WHERE {",
|
|
660
|
+
" ?lib a ds:ImplementationLibrary ;",
|
|
661
|
+
" ds:libraryName ?library .",
|
|
662
|
+
"}",
|
|
663
|
+
].join("\n"),
|
|
664
|
+
},
|
|
555
665
|
description: "Filter by implementation library name.",
|
|
556
666
|
},
|
|
557
667
|
],
|
|
@@ -618,20 +728,44 @@ const codeStandardsStories: readonly PackDefinition[] = [
|
|
|
618
728
|
noun: "standard",
|
|
619
729
|
description: "List all code standards.",
|
|
620
730
|
toolDescription:
|
|
621
|
-
|
|
731
|
+
'List code standards: one ROW per standard — its IRI, name, category and description — not the standards themselves. Take a row\'s `name` VERBATIM to standard_lookup for the dos and donts. Optionally filter by category slug (a parent slug answers for its whole branch; standard_categories lists them) or by search term. Example: standard_list { category: "react" }.',
|
|
622
732
|
list: {
|
|
623
733
|
query: [
|
|
734
|
+
// `?category` is the LEAF a standard is filed under — what a row
|
|
735
|
+
// displays. `?categories` is that leaf plus every ancestor, which is
|
|
736
|
+
// what `--category` matches against, so asking for a parent answers for
|
|
737
|
+
// the whole branch. The traversal is written ONCE, here, rather than
|
|
738
|
+
// repeated by each consumer.
|
|
624
739
|
"SELECT ?uri ?name ?category ?description",
|
|
740
|
+
' (GROUP_CONCAT(DISTINCT ?ancestorSlug; SEPARATOR=" ") AS ?categories)',
|
|
625
741
|
"WHERE {",
|
|
626
742
|
" ?uri a cs:CodeStandard ;",
|
|
627
743
|
" cs:description ?description .",
|
|
628
|
-
|
|
744
|
+
// `rdfs:label`, matching `lookup.by` below. Both COALESCE over the
|
|
745
|
+
// SAME property with the SAME IRI fallback, and that agreement IS the
|
|
746
|
+
// two-step grammar: a row's `name` goes VERBATIM to lookup. Keyed on
|
|
747
|
+
// different properties they diverge for exactly the entities carrying
|
|
748
|
+
// one and not the other — 16 standards in the shipped snapshot
|
|
749
|
+
// published `Turtle local-name casing` from `cs:name` while lookup,
|
|
750
|
+
// reading `rdfs:label`, bound the derived slug and answered
|
|
751
|
+
// ENTITY_NOT_FOUND. Change one, change both.
|
|
752
|
+
" OPTIONAL { ?uri rdfs:label ?n . }",
|
|
629
753
|
' BIND(COALESCE(?n, REPLACE(STRAFTER(STR(?uri), "#"), "\\\\.", "/")) AS ?name)',
|
|
630
754
|
" OPTIONAL {",
|
|
631
755
|
" ?uri cs:hasCategory ?cat .",
|
|
632
756
|
" ?cat cs:slug ?category .",
|
|
757
|
+
// `skos:broader` is deliberately NOT transitive, and this store
|
|
758
|
+
// (oxigraph) has no reasoner — so `skos:broaderTransitive` returns zero
|
|
759
|
+
// rows and hand-asserting it would be materialisation wearing a
|
|
760
|
+
// standards badge. `broader*` is the only thing that works.
|
|
761
|
+
// The `*` is REFLEXIVE and that is load-bearing: `+` would silently
|
|
762
|
+
// drop every standard filed DIRECTLY on the category being asked for
|
|
763
|
+
// (one of the 8 under `testing` today). Do not "correct" it.
|
|
764
|
+
" ?cat skos:broader* ?ancestor .",
|
|
765
|
+
" ?ancestor cs:slug ?ancestorSlug .",
|
|
633
766
|
" }",
|
|
634
767
|
"}",
|
|
768
|
+
"GROUP BY ?uri ?name ?category ?description",
|
|
635
769
|
"ORDER BY ?name",
|
|
636
770
|
].join("\n"),
|
|
637
771
|
columns: [
|
|
@@ -643,28 +777,64 @@ const codeStandardsStories: readonly PackDefinition[] = [
|
|
|
643
777
|
filters: [
|
|
644
778
|
{
|
|
645
779
|
param: "category",
|
|
646
|
-
variable: "
|
|
647
|
-
|
|
780
|
+
variable: "categories",
|
|
781
|
+
match: "set",
|
|
782
|
+
// The SAME terms `standard categories` enumerates (`cs:Category` /
|
|
783
|
+
// `cs:slug`), so the slugs that surface hands out are exactly the
|
|
784
|
+
// slugs this filter accepts. Read from the graph rather than the
|
|
785
|
+
// returned ROWS: a category the graph declares with no standards
|
|
786
|
+
// filed under it is reported by `standard categories` with count 0,
|
|
787
|
+
// and asking for it must be the documented calm empty list, not
|
|
788
|
+
// INVALID_INPUT.
|
|
789
|
+
vocabulary: {
|
|
790
|
+
query: [
|
|
791
|
+
"SELECT DISTINCT ?slug WHERE {",
|
|
792
|
+
" ?cat a cs:Category ;",
|
|
793
|
+
" cs:slug ?slug .",
|
|
794
|
+
"}",
|
|
795
|
+
].join("\n"),
|
|
796
|
+
variable: "slug",
|
|
797
|
+
},
|
|
798
|
+
description:
|
|
799
|
+
"Filter by category slug. A parent category answers for its whole branch.",
|
|
648
800
|
},
|
|
649
801
|
],
|
|
650
802
|
search: {
|
|
651
803
|
variables: ["name", "description"],
|
|
652
804
|
description: "Search in name and description.",
|
|
653
805
|
},
|
|
806
|
+
// Deliberately NOT `sources update`: the code standards ship in the
|
|
807
|
+
// embedded snapshot and answer with no update at all, so the generic
|
|
808
|
+
// build hint is actively wrong here. An empty result on this noun means
|
|
809
|
+
// the filter, and the vocabulary it must be drawn from lives in the graph
|
|
810
|
+
// — which is what `standard categories` reads out.
|
|
811
|
+
emptyRecovery: {
|
|
812
|
+
message:
|
|
813
|
+
"Category slugs come from the graph, and a parent slug answers for its whole branch — read them out rather than guessing.",
|
|
814
|
+
cli: "standard categories",
|
|
815
|
+
},
|
|
654
816
|
},
|
|
655
817
|
verbs: [
|
|
656
818
|
{
|
|
657
819
|
verb: "categories",
|
|
658
|
-
description:
|
|
659
|
-
|
|
820
|
+
description:
|
|
821
|
+
"List all standard categories with counts (a parent counts its whole branch).",
|
|
822
|
+
toolDescription:
|
|
823
|
+
"List all code standard categories with the number of standards each covers. Categories are a hierarchy: a parent's count includes every descendant, and `standard_list { category }` answers for the same set. Use this to pick a valid slug before filtering. Example: standard_categories {}.",
|
|
660
824
|
query: [
|
|
661
|
-
|
|
825
|
+
// The same reflexive roll-up `list` filters with — written the other
|
|
826
|
+
// way round (every category whose broader-chain reaches ?cat), so the
|
|
827
|
+
// count a category reports and the rows `--category` returns are the
|
|
828
|
+
// same set. `COUNT(DISTINCT ?standard)`: a standard reachable by two
|
|
829
|
+
// paths is still one standard.
|
|
830
|
+
"SELECT ?name (COUNT(DISTINCT ?standard) AS ?count)",
|
|
662
831
|
"WHERE {",
|
|
663
832
|
" ?cat a cs:Category ;",
|
|
664
833
|
" cs:slug ?name .",
|
|
665
834
|
" OPTIONAL {",
|
|
835
|
+
" ?descendant skos:broader* ?cat .",
|
|
666
836
|
" ?standard a cs:CodeStandard ;",
|
|
667
|
-
" cs:hasCategory ?
|
|
837
|
+
" cs:hasCategory ?descendant .",
|
|
668
838
|
" }",
|
|
669
839
|
"}",
|
|
670
840
|
"GROUP BY ?name",
|
|
@@ -674,16 +844,43 @@ const codeStandardsStories: readonly PackDefinition[] = [
|
|
|
674
844
|
{ field: "name", label: "Category" },
|
|
675
845
|
{ field: "count", label: "Standards" },
|
|
676
846
|
],
|
|
847
|
+
// Also not `sources update`. The categories ride the same embedded
|
|
848
|
+
// snapshot, so zero rows means the store did not load — a health
|
|
849
|
+
// question, not a staleness one.
|
|
850
|
+
emptyRecovery: {
|
|
851
|
+
message:
|
|
852
|
+
"The code standards ship with the CLI itself, so no categories at all means the store did not load — not that it is out of date.",
|
|
853
|
+
cli: "doctor",
|
|
854
|
+
},
|
|
677
855
|
},
|
|
678
856
|
],
|
|
679
857
|
lookup: {
|
|
680
858
|
source: "sparql",
|
|
681
|
-
|
|
859
|
+
// `rdfs:label`, not `cs:name`. The pack pin above moved to v0.1.5, which
|
|
860
|
+
// retired the bespoke `cs:name` for the standard property every RDF
|
|
861
|
+
// consumer already reads — measured against that tag: 0 standards carry
|
|
862
|
+
// `cs:name`, 148 of 148 carry exactly one `rdfs:label`. Left keyed on the
|
|
863
|
+
// retired property, this story would still ANSWER — every title would
|
|
864
|
+
// simply stop reaching a reader and each row would fall back to its
|
|
865
|
+
// IRI-derived name, with nothing raised. That is the same silent shape as
|
|
866
|
+
// reading a retired `ds:whenToUse`, one noun over.
|
|
867
|
+
by: "rdfs:label",
|
|
868
|
+
// The fallback stays, and is now near-inert rather than load-bearing: it
|
|
869
|
+
// covered the ~87% of standards that carried no display title at all, and
|
|
870
|
+
// v0.1.5 gives every one of them a curated label. It remains declared
|
|
871
|
+
// because a pack is data — a future release that drops a label should
|
|
872
|
+
// degrade to the IRI-derived name, not become unaddressable.
|
|
873
|
+
//
|
|
874
|
+
// Deliberately NOT declared on `block`/`token`/`tier`/`concept`: each of
|
|
875
|
+
// those lists REQUIRES its `by` property, so an entity without one is a
|
|
876
|
+
// row they never publish, and making it addressable (or sampleable) here
|
|
877
|
+
// would be the mirror of the defect this repairs.
|
|
878
|
+
nameFallback: "iri",
|
|
682
879
|
type: "cs:CodeStandard",
|
|
683
880
|
description:
|
|
684
|
-
"Look up
|
|
881
|
+
"Look up one or more standards by name, IRI, or glob. --detail standard adds the dos, --detail detailed adds the don'ts.",
|
|
685
882
|
toolDescription:
|
|
686
|
-
|
|
883
|
+
'Get one or more code standards in full, with dos and don\'ts as code examples. `detail` DEFAULTS to "summary", which returns neither: pass detail: "standard" for the dos and detail: "detailed" for dos AND don\'ts. Address a standard by the name standard_list publishes (`react/component/tsdoc`), by prefixed name (`cs:react.component.tsdoc`), by absolute IRI, or by a glob over any of those. Example: standard_lookup { name: ["react/component/tsdoc"], detail: "detailed" }.',
|
|
687
884
|
fields: [
|
|
688
885
|
{
|
|
689
886
|
name: "category",
|
|
@@ -729,7 +926,7 @@ const codeStandardsStories: readonly PackDefinition[] = [
|
|
|
729
926
|
description:
|
|
730
927
|
"Return randomly selected complete standard instances as exemplars for shape discovery.",
|
|
731
928
|
toolDescription:
|
|
732
|
-
"Return 1–5 randomly selected complete code standard instances as exemplars. Use BEFORE writing queries to see actual data shapes, property names, and value formats. Each call returns different instances.",
|
|
929
|
+
"Return 1–5 randomly selected complete code standard instances as exemplars. Use BEFORE writing queries to see actual data shapes, property names, and value formats. Each call returns different instances. Example: standard_sample { count: 2 }.",
|
|
733
930
|
},
|
|
734
931
|
},
|
|
735
932
|
},
|
|
@@ -785,9 +982,19 @@ Made by the Canonical Webteam — https://canonical.com.`,
|
|
|
785
982
|
name: "@canonical/anatomy-dsl",
|
|
786
983
|
source: "git+https://github.com/canonical/anatomy-dsl.git#main",
|
|
787
984
|
},
|
|
985
|
+
// Pinned to a TAG, and the only source here that is. The standards are the
|
|
986
|
+
// pack an agent is most likely to quote back at a human as policy, so which
|
|
987
|
+
// revision answered a query has to be recoverable — a floating ref makes
|
|
988
|
+
// "the CLI told me this was the rule" unfalsifiable. The other three still
|
|
989
|
+
// float: they are read for shape and identity, where the newest answer is
|
|
990
|
+
// the right one.
|
|
991
|
+
//
|
|
992
|
+
// Bump this deliberately. `sources update` resolves the tag, so a new
|
|
993
|
+
// upstream release reaches users only when this line moves — which is the
|
|
994
|
+
// point, and the cost.
|
|
788
995
|
{
|
|
789
996
|
name: "@canonical/code-standards",
|
|
790
|
-
source: "git+https://github.com/canonical/web-code-standards.git#
|
|
997
|
+
source: "git+https://github.com/canonical/web-code-standards.git#v0.1.5",
|
|
791
998
|
stories: codeStandardsStories,
|
|
792
999
|
},
|
|
793
1000
|
// The implementation graph: ds:ImplementationLibrary / ds:ImplementationObject
|
package/src/bin.ts
CHANGED
|
@@ -204,7 +204,14 @@ async function main(): Promise<void> {
|
|
|
204
204
|
.flatMap((module) => [...module.verbs])
|
|
205
205
|
.filter((verb) => !verb.hidden);
|
|
206
206
|
process.stdout.write(
|
|
207
|
-
`${formatRootHelp(
|
|
207
|
+
`${formatRootHelp(
|
|
208
|
+
BIN_NAME,
|
|
209
|
+
PROGRAM_DESCRIPTION,
|
|
210
|
+
live,
|
|
211
|
+
VERSION,
|
|
212
|
+
ISSUES_URL,
|
|
213
|
+
globalFlags,
|
|
214
|
+
)}\n`,
|
|
208
215
|
);
|
|
209
216
|
// The front door is a read, so it is where the un-set-up hint belongs: the
|
|
210
217
|
// machine's state is the presence of the global config, and nothing is
|
|
@@ -17,8 +17,11 @@
|
|
|
17
17
|
* deleted `capabilities/block/parity.test.ts`. Button and Modal resolve with
|
|
18
18
|
* the same content a direct SPARQL oracle returns (summary, guidance,
|
|
19
19
|
* anatomy, tier, modifier families with values, properties, subcomponents).
|
|
20
|
-
* The fixture
|
|
21
|
-
*
|
|
20
|
+
* The fixture declares the usage narrative the way the live graph does — one
|
|
21
|
+
* `ds:usage` literal — so what is exercised here is the path a real install
|
|
22
|
+
* takes. It formerly declared the retired whenToUse/whenNotToUse pair, and
|
|
23
|
+
* that divergence is exactly why this suite could assert a "### When to use"
|
|
24
|
+
* heading no install had rendered in months.
|
|
22
25
|
*/
|
|
23
26
|
|
|
24
27
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
@@ -139,9 +142,9 @@ ds:Component a owl:Class .
|
|
|
139
142
|
const rows = (await verb("list").run({}, emptyRt)) as PackRow[];
|
|
140
143
|
expect(rows).toEqual([]);
|
|
141
144
|
// The same semantics, on the empty-state seam: the calm message + its
|
|
142
|
-
// runnable hint now reach the user via stderr (`
|
|
145
|
+
// runnable hint now reach the user via stderr (`notice`), keeping
|
|
143
146
|
// plain stdout pure data.
|
|
144
|
-
const notice = verb("list").output.formatters.
|
|
147
|
+
const notice = verb("list").output.formatters.notice?.(rows);
|
|
145
148
|
expect(notice).toContain("No blocks in the store.");
|
|
146
149
|
expect(notice).toContain("pragma sources update");
|
|
147
150
|
} finally {
|
|
@@ -159,10 +162,7 @@ describe("block lookup — Button content parity (GraphQL, detailed)", () => {
|
|
|
159
162
|
|
|
160
163
|
// Guidance + anatomy sections — each cross-checked against the graph.
|
|
161
164
|
expect(button.summary).toBe(await oracle(`${DS}button`, "ds:summary"));
|
|
162
|
-
expect(button.
|
|
163
|
-
expect(button.whenNotToUse).toBe(
|
|
164
|
-
await oracle(`${DS}button`, "ds:whenNotToUse"),
|
|
165
|
-
);
|
|
165
|
+
expect(button.usage).toBe(await oracle(`${DS}button`, "ds:usage"));
|
|
166
166
|
expect(button.guidelines).toBe(
|
|
167
167
|
await oracle(`${DS}button`, "ds:guidelines"),
|
|
168
168
|
);
|
|
@@ -200,7 +200,13 @@ describe("block lookup — Button content parity (GraphQL, detailed)", () => {
|
|
|
200
200
|
const out = (await verb("lookup").run({ name: ["Button"] }, rt)) as never;
|
|
201
201
|
const llm = verb("lookup").output.formatters.llm(out);
|
|
202
202
|
expect(llm).toContain("## Button");
|
|
203
|
-
expect(llm).toContain("###
|
|
203
|
+
expect(llm).toContain("### Usage");
|
|
204
|
+
// The usage literal's OWN headings are demoted below the section heading
|
|
205
|
+
// they now live under, so `### When to use` renders as a CHILD of Usage
|
|
206
|
+
// rather than a sibling that reads as an empty section.
|
|
207
|
+
expect(llm).toContain("#### When to use");
|
|
208
|
+
expect(llm).toContain("#### When not to use");
|
|
209
|
+
expect(llm).not.toContain("\n### When to use\n");
|
|
204
210
|
expect(llm).toContain("### Anatomy (DSL)");
|
|
205
211
|
expect(llm).toContain("### Modifier Families");
|
|
206
212
|
expect(llm).toContain("primary");
|
|
@@ -213,7 +219,15 @@ describe("block lookup — Modal content parity (GraphQL, detailed)", () => {
|
|
|
213
219
|
expect(modal.uri).toBe(`${DS}modal`);
|
|
214
220
|
expect(modal.name).toBe("Modal");
|
|
215
221
|
expect(modal.summary).toBe(await oracle(`${DS}modal`, "ds:summary"));
|
|
216
|
-
|
|
222
|
+
// Modal asserts an EMPTY `ds:usage` — the shape 138 of the 264 live blocks
|
|
223
|
+
// have. It resolves (parity with the oracle) and renders NOTHING: an empty
|
|
224
|
+
// literal must not print a bare "### Usage" heading with no body under it.
|
|
225
|
+
expect(modal.usage).toBe(await oracle(`${DS}modal`, "ds:usage"));
|
|
226
|
+
expect(modal.usage).toBe("");
|
|
227
|
+
const modalLlm = verb("lookup").output.formatters.llm(
|
|
228
|
+
(await verb("lookup").run({ name: ["Modal"] }, rt)) as never,
|
|
229
|
+
);
|
|
230
|
+
expect(modalLlm).not.toContain("### Usage");
|
|
217
231
|
const families = modal.modifierFamilies as {
|
|
218
232
|
name: string;
|
|
219
233
|
values?: string[];
|
|
@@ -237,7 +251,7 @@ describe("block lookup — disclosure trims to the base view at summary", () =>
|
|
|
237
251
|
const button = out.results.at(0) as Record<string, unknown>;
|
|
238
252
|
expect(button.name).toBe("Button");
|
|
239
253
|
expect(button.summary).toBeDefined();
|
|
240
|
-
expect(button.
|
|
254
|
+
expect(button.usage).toBeUndefined();
|
|
241
255
|
expect(button.anatomyDsl).toBeUndefined();
|
|
242
256
|
expect(button.modifierFamilies).toBeUndefined();
|
|
243
257
|
expect(button.figmaLink).toBeUndefined();
|