@canonical/pragma-cli 0.36.0 → 0.38.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 +3 -2
- package/bundled-skills/adoption-a1-styles/SKILL.md +24 -0
- package/bundled-skills/adoption-a2-components/SKILL.md +22 -6
- package/bundled-skills/anatomy-author/ANATOMY_DSL_SPEC.md +1397 -327
- package/bundled-skills/anatomy-author/SKILL.md +840 -137
- package/bundled-skills/design-auditor/SKILL.md +133 -9
- package/bundled-skills/implement-component/SKILL.md +192 -23
- package/bundled-skills/specify-component/SKILL.md +124 -12
- package/bundled-skills/specify-pattern/SKILL.md +47 -8
- package/dist/package.json +23 -20
- package/dist/pragma.conf.js +963 -40
- package/dist/pragma.conf.js.map +1 -1
- package/dist/src/capabilities/capabilities/catalog.js +14 -5
- package/dist/src/capabilities/capabilities/catalog.js.map +1 -1
- package/dist/src/capabilities/capabilities/hints.js +33 -5
- package/dist/src/capabilities/capabilities/hints.js.map +1 -1
- package/dist/src/capabilities/config/show.render.js +30 -2
- package/dist/src/capabilities/config/show.render.js.map +1 -1
- package/dist/src/capabilities/create/create.verb.js +2 -1
- package/dist/src/capabilities/create/create.verb.js.map +1 -1
- package/dist/src/capabilities/create/createSurface.generated.js +23 -1
- package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkNodeVersion.js +11 -6
- package/dist/src/capabilities/doctor/checks/checkNodeVersion.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/harnessInventory.js +1 -1
- package/dist/src/capabilities/doctor/checks/harnessInventory.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js +38 -0
- package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js.map +1 -0
- package/dist/src/capabilities/doctor/checks/targetHealth.js +104 -14
- package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
- package/dist/src/capabilities/graph/connect.render.js +101 -0
- package/dist/src/capabilities/graph/connect.render.js.map +1 -0
- package/dist/src/capabilities/graph/connect.types.js +21 -0
- package/dist/src/capabilities/graph/connect.types.js.map +1 -0
- package/dist/src/capabilities/graph/connect.verb.js +147 -0
- package/dist/src/capabilities/graph/connect.verb.js.map +1 -0
- package/dist/src/capabilities/graph/index.js +5 -3
- package/dist/src/capabilities/graph/index.js.map +1 -1
- package/dist/src/capabilities/graph/queryText.js +206 -0
- package/dist/src/capabilities/graph/queryText.js.map +1 -0
- package/dist/src/capabilities/graph/relationIndex.js +302 -0
- package/dist/src/capabilities/graph/relationIndex.js.map +1 -0
- package/dist/src/capabilities/graph/runConnect.js +456 -0
- package/dist/src/capabilities/graph/runConnect.js.map +1 -0
- package/dist/src/capabilities/graph/runQuery.js +21 -4
- package/dist/src/capabilities/graph/runQuery.js.map +1 -1
- package/dist/src/capabilities/setup/buildPlan.js +6 -2
- package/dist/src/capabilities/setup/buildPlan.js.map +1 -1
- package/dist/src/capabilities/setup/operations/index.js +7 -2
- package/dist/src/capabilities/setup/operations/index.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupCompletions.js +6 -2
- package/dist/src/capabilities/setup/operations/setupCompletions.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupConfig.js +4 -2
- package/dist/src/capabilities/setup/operations/setupConfig.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupGenerator.js +72 -14
- package/dist/src/capabilities/setup/operations/setupGenerator.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupLsp.js +372 -62
- package/dist/src/capabilities/setup/operations/setupLsp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupMcp.js +150 -5
- package/dist/src/capabilities/setup/operations/setupMcp.js.map +1 -1
- package/dist/src/capabilities/setup/operations/setupSkills.js +4 -2
- package/dist/src/capabilities/setup/operations/setupSkills.js.map +1 -1
- package/dist/src/capabilities/setup/operations/writability.js +114 -0
- package/dist/src/capabilities/setup/operations/writability.js.map +1 -0
- package/dist/src/capabilities/setup/plan.js.map +1 -1
- package/dist/src/capabilities/setup/setup.verb.js +80 -31
- package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
- package/dist/src/capabilities/setup/targets.js +124 -42
- package/dist/src/capabilities/setup/targets.js.map +1 -1
- package/dist/src/capabilities/shared/index.js +1 -1
- package/dist/src/capabilities/shared/index.js.map +1 -1
- package/dist/src/constants.js +7 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/error/renderError.js +3 -2
- package/dist/src/kernel/error/renderError.js.map +1 -1
- package/dist/src/kernel/error/validOptions.js +41 -0
- package/dist/src/kernel/error/validOptions.js.map +1 -0
- package/dist/src/kernel/packs/compile.js +90 -6
- package/dist/src/kernel/packs/compile.js.map +1 -1
- package/dist/src/kernel/packs/cursor.js +135 -0
- package/dist/src/kernel/packs/cursor.js.map +1 -0
- package/dist/src/kernel/packs/graphql/buildLookupDocument.js +9 -2
- package/dist/src/kernel/packs/graphql/buildLookupDocument.js.map +1 -1
- package/dist/src/kernel/packs/paging.js +108 -0
- package/dist/src/kernel/packs/paging.js.map +1 -0
- package/dist/src/kernel/packs/renderPack.js +154 -5
- package/dist/src/kernel/packs/renderPack.js.map +1 -1
- package/dist/src/kernel/packs/resolveEntity.js +118 -19
- package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
- package/dist/src/kernel/packs/runBodies.js +156 -18
- package/dist/src/kernel/packs/runBodies.js.map +1 -1
- package/dist/src/kernel/packs/schema.js +160 -12
- package/dist/src/kernel/packs/schema.js.map +1 -1
- package/dist/src/kernel/packs/sparql/authorQuery.js +227 -0
- package/dist/src/kernel/packs/sparql/authorQuery.js.map +1 -0
- package/dist/src/kernel/packs/sparql/buildListQuery.js +251 -0
- package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -0
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js +125 -22
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
- package/dist/src/kernel/packs/sparql/filterValues.js +145 -0
- package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -0
- package/dist/src/kernel/packs/sparql/index.js +24 -14
- package/dist/src/kernel/packs/sparql/index.js.map +1 -1
- package/dist/src/kernel/packs/sparql/runSelect.js +10 -4
- package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
- package/dist/src/kernel/packs/sparql/searchTerm.js +25 -0
- package/dist/src/kernel/packs/sparql/searchTerm.js.map +1 -0
- package/dist/src/kernel/packs/storyRules.js +151 -0
- package/dist/src/kernel/packs/storyRules.js.map +1 -0
- package/dist/src/kernel/packs/tierScope.js +310 -0
- package/dist/src/kernel/packs/tierScope.js.map +1 -0
- package/dist/src/kernel/packs/types.js +80 -0
- package/dist/src/kernel/packs/types.js.map +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js +10 -1
- package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
- package/dist/src/kernel/project/cli/dispatch.js +104 -3
- package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
- package/dist/src/kernel/project/cli/rootHelp.js +8 -5
- package/dist/src/kernel/project/cli/rootHelp.js.map +1 -1
- package/dist/src/kernel/project/cli/suggestNames.js +31 -7
- package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
- package/dist/src/kernel/project/mcp/registerVerb.js +5 -1
- package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
- package/dist/src/kernel/render/renderers.js +34 -2
- package/dist/src/kernel/render/renderers.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js +2 -3
- package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js +4 -0
- package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js.map +1 -0
- package/dist/src/kernel/runtime/graphpack/embedded.js +13 -6
- package/dist/src/kernel/runtime/graphpack/embedded.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/read.js +17 -10
- package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
- package/dist/src/kernel/runtime/loadSession.js +3 -1
- package/dist/src/kernel/runtime/loadSession.js.map +1 -1
- package/dist/src/kernel/runtime/probe.js +1 -1
- package/dist/src/kernel/runtime/probe.js.map +1 -1
- package/dist/src/kernel/runtime/readEntity.js +19 -4
- package/dist/src/kernel/runtime/readEntity.js.map +1 -1
- package/dist/src/kernel/runtime/refs/parseRef.js +17 -1
- package/dist/src/kernel/runtime/refs/parseRef.js.map +1 -1
- package/dist/src/kernel/runtime/refs/resolve.js +38 -5
- package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
- package/dist/src/kernel/spec/emitReference.js +1 -1
- package/dist/src/kernel/spec/emitReference.js.map +1 -1
- package/package.json +23 -20
- package/pragma.conf.ts +983 -40
- package/src/capabilities/block.parity.test.ts +207 -27
- package/src/capabilities/block.shipped.exec.test.ts +156 -14
- package/src/capabilities/block.tierRank.exec.test.ts +46 -9
- package/src/capabilities/capabilities/catalog.ts +14 -5
- package/src/capabilities/capabilities/hints.ts +40 -5
- package/src/capabilities/config/collectConfigShow.test.ts +1 -0
- package/src/capabilities/config/set.test.ts +24 -25
- package/src/capabilities/config/show.render.test.ts +9 -4
- package/src/capabilities/config/show.render.ts +30 -2
- package/src/capabilities/create/byteEquality.test.ts +28 -1
- package/src/capabilities/create/create.test.ts +1 -0
- package/src/capabilities/create/create.verb.ts +2 -1
- package/src/capabilities/create/createGrammar.test.ts +4 -1
- package/src/capabilities/create/createSurface.generated.ts +23 -1
- package/src/capabilities/create/crossCli.subprocess.test.ts +10 -3
- package/src/capabilities/distribution.parity.test.ts +12 -11
- package/src/capabilities/distribution.test.ts +77 -7
- package/src/capabilities/doctor/checks/checkNodeVersion.test.ts +49 -0
- package/src/capabilities/doctor/checks/checkNodeVersion.ts +11 -7
- package/src/capabilities/doctor/checks/harnessInventory.test.ts +13 -6
- package/src/capabilities/doctor/checks/harnessInventory.ts +8 -4
- package/src/capabilities/doctor/checks/isSupportedNodeVersion.test.ts +111 -0
- package/src/capabilities/doctor/checks/isSupportedNodeVersion.ts +34 -0
- package/src/capabilities/doctor/checks/mcpCommand.test.ts +7 -1
- package/src/capabilities/doctor/checks/targetHealth.ts +114 -13
- package/src/capabilities/doctor/doctor.test.ts +327 -36
- package/src/capabilities/emptyRecovery.test.ts +84 -28
- package/src/capabilities/graph/connect.render.ts +141 -0
- package/src/capabilities/graph/connect.shipped.exec.test.ts +370 -0
- package/src/capabilities/graph/connect.test.ts +361 -0
- package/src/capabilities/graph/connect.types.ts +136 -0
- package/src/capabilities/graph/connect.verb.ts +165 -0
- package/src/capabilities/graph/index.ts +5 -3
- package/src/capabilities/graph/query.shipped.exec.test.ts +66 -0
- package/src/capabilities/graph/query.test.ts +17 -0
- package/src/capabilities/graph/queryText.test.ts +121 -0
- package/src/capabilities/graph/queryText.ts +240 -0
- package/src/capabilities/graph/relationIndex.ts +372 -0
- package/src/capabilities/graph/runConnect.ts +577 -0
- package/src/capabilities/graph/runQuery.ts +21 -6
- package/src/capabilities/lazy.test.ts +32 -2
- package/src/capabilities/listBudget.shipped.exec.test.ts +239 -0
- package/src/capabilities/listLookup.shipped.exec.test.ts +387 -0
- package/src/capabilities/listQuery.shipped.exec.test.ts +400 -0
- package/src/capabilities/resources/resources.test.ts +38 -2
- package/src/capabilities/setup/buildPlan.ts +7 -1
- package/src/capabilities/setup/operations/index.ts +14 -0
- package/src/capabilities/setup/operations/setupCompletions.ts +9 -2
- package/src/capabilities/setup/operations/setupConfig.ts +7 -2
- package/src/capabilities/setup/operations/setupGenerator.ts +93 -15
- package/src/capabilities/setup/operations/setupLsp.ts +544 -85
- package/src/capabilities/setup/operations/setupMcp.ts +212 -4
- package/src/capabilities/setup/operations/setupSkills.ts +7 -2
- package/src/capabilities/setup/operations/writability.test.ts +151 -0
- package/src/capabilities/setup/operations/writability.ts +135 -0
- package/src/capabilities/setup/plan.ts +11 -0
- package/src/capabilities/setup/setup.test.ts +992 -16
- package/src/capabilities/setup/setup.verb.ts +84 -36
- package/src/capabilities/setup/targets.ts +152 -48
- package/src/capabilities/setup/types.ts +41 -5
- package/src/capabilities/shared/index.ts +1 -0
- package/src/capabilities/sources/sources.test.ts +55 -0
- package/src/capabilities/surface.test.ts +59 -11
- package/src/capabilities/tier.parity.test.ts +2 -2
- package/src/capabilities/token.parity.test.ts +784 -0
- package/src/capabilities/tokenGraph.cli.test.ts +279 -0
- package/src/capabilities/tokenGraph.shipped.exec.test.ts +653 -0
- package/src/capabilities/variable.parity.test.ts +448 -0
- package/src/constants.ts +8 -0
- package/src/kernel/completion/shellDrive.test.ts +32 -30
- package/src/kernel/config/defaults.test.ts +21 -2
- package/src/kernel/config/readConfig.test.ts +1 -1
- package/src/kernel/error/renderError.ts +3 -2
- package/src/kernel/error/validOptions.test.ts +57 -0
- package/src/kernel/error/validOptions.ts +45 -0
- package/src/kernel/packs/collect.test.ts +2 -0
- package/src/kernel/packs/compile.test.ts +188 -15
- package/src/kernel/packs/compile.ts +109 -14
- package/src/kernel/packs/cursor.ts +135 -0
- package/src/kernel/packs/filteredEmpty.test.ts +213 -0
- package/src/kernel/packs/graphql/buildLookupDocument.ts +16 -9
- package/src/kernel/packs/graphqlSource.test.ts +152 -0
- package/src/kernel/packs/listNotice.test.ts +156 -0
- package/src/kernel/packs/paging.ts +110 -0
- package/src/kernel/packs/renderPack.ts +186 -13
- package/src/kernel/packs/resolveEntity.test.ts +62 -3
- package/src/kernel/packs/resolveEntity.ts +186 -26
- package/src/kernel/packs/runBodies.ts +196 -26
- package/src/kernel/packs/schema.ts +180 -13
- package/src/kernel/packs/sparql/authorQuery.test.ts +179 -0
- package/src/kernel/packs/sparql/authorQuery.ts +257 -0
- package/src/kernel/packs/sparql/buildListQuery.test.ts +344 -0
- package/src/kernel/packs/sparql/buildListQuery.ts +344 -0
- package/src/kernel/packs/sparql/buildLookupQuery.test.ts +138 -0
- package/src/kernel/packs/sparql/buildLookupQuery.ts +140 -20
- package/src/kernel/packs/sparql/filterValues.test.ts +86 -0
- package/src/kernel/packs/sparql/filterValues.ts +182 -0
- package/src/kernel/packs/sparql/index.ts +30 -14
- package/src/kernel/packs/sparql/runSelect.test.ts +63 -0
- package/src/kernel/packs/sparql/runSelect.ts +42 -2
- package/src/kernel/packs/sparql/searchTerm.ts +29 -0
- package/src/kernel/packs/storyRules.ts +180 -0
- package/src/kernel/packs/tierScope.test.ts +487 -0
- package/src/kernel/packs/tierScope.ts +409 -0
- package/src/kernel/packs/toolDescription.test.ts +13 -10
- package/src/kernel/packs/types.ts +311 -9
- package/src/kernel/project/cli/buildProgram.ts +17 -1
- package/src/kernel/project/cli/dispatch.test.ts +87 -0
- package/src/kernel/project/cli/dispatch.ts +114 -4
- package/src/kernel/project/cli/rootHelp.ts +8 -5
- package/src/kernel/project/cli/suggest.test.ts +35 -0
- package/src/kernel/project/cli/suggestNames.ts +34 -7
- package/src/kernel/project/mcp/registerVerb.ts +5 -1
- package/src/kernel/render/contracts.ts +2 -0
- package/src/kernel/render/prefixes.test.ts +2 -0
- package/src/kernel/render/renderers.test.ts +43 -0
- package/src/kernel/render/renderers.ts +34 -1
- package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +2 -3
- package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +1 -1
- package/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.ts +3 -0
- package/src/kernel/runtime/graphpack/embedded.ts +14 -6
- package/src/kernel/runtime/graphpack/graphpack.test.ts +31 -5
- package/src/kernel/runtime/graphpack/read.ts +17 -13
- package/src/kernel/runtime/loadSession.ts +3 -1
- package/src/kernel/runtime/probe.ts +1 -1
- package/src/kernel/runtime/readEntity.ts +19 -4
- package/src/kernel/runtime/refs/parseRef.test.ts +49 -1
- package/src/kernel/runtime/refs/parseRef.ts +25 -1
- package/src/kernel/runtime/refs/resolve.ts +39 -5
- package/src/kernel/runtime/types.ts +30 -0
- package/src/kernel/spec/emitReference.ts +1 -1
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/types.ts +17 -0
- package/src/testing/PARITY_GAPS.ts +4 -4
- package/src/testing/behavioral/agentSession.mcp.test.ts +43 -39
- package/src/testing/behavioral/completion.test.ts +7 -6
- package/src/testing/behavioral/disclosure.test.ts +39 -37
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +82 -64
- package/src/testing/behavioral/errorMatrix.storeless.test.ts +11 -10
- package/src/testing/behavioral/journeys.cli.test.ts +71 -32
- package/src/testing/behavioral/journeys.defaultPack.test.ts +6 -4
- package/src/testing/behavioral/journeys.firstInstall.test.ts +70 -5
- package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +4 -3
- package/src/testing/behavioral/journeys.packageStories.test.ts +2 -1
- package/src/testing/behavioral/mcpSurface.test.ts +28 -25
- package/src/testing/behavioral/parity.test.ts +25 -23
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +20 -0
- package/src/testing/eval/cases/effectful.ts +7 -1
- package/src/testing/eval/cases/readNouns.ts +100 -11
- package/src/testing/fixtures/blockGraph.ts +89 -5
- package/src/testing/fixtures/connectGraph.ts +159 -0
- package/src/testing/fixtures/graph/canonical.ts +128 -32
- package/src/testing/helpers/fsProbe.ts +88 -0
- package/src/testing/helpers/runCli.test.ts +44 -0
- package/src/testing/helpers/runCli.ts +27 -3
- package/src/testing/perf/budgets.test.ts +3 -1
- package/src/testing/perf/budgets.ts +138 -54
- package/dist/src/kernel/packs/sparql/applyFilters.js +0 -167
- package/dist/src/kernel/packs/sparql/applyFilters.js.map +0 -1
- package/dist/src/kernel/packs/sparql/applySearch.js +0 -25
- package/dist/src/kernel/packs/sparql/applySearch.js.map +0 -1
- package/src/kernel/packs/sparql/applyFilters.ts +0 -203
- package/src/kernel/packs/sparql/applySearch.ts +0 -33
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tier scope: which tiers a read of a tiered noun answers from.
|
|
3
|
+
*
|
|
4
|
+
* WHAT IT IS FOR. The design system's tier hierarchy has two levels — five
|
|
5
|
+
* top-level tiers (`global`, `apps`, `sites`, `documentation`, `stores`) and
|
|
6
|
+
* ten second-level ones beneath `apps` and `sites` — and every read used to
|
|
7
|
+
* answer from all fifteen at once. `block list` printed 252 blocks, a third of
|
|
8
|
+
* them belonging to one product's own screens; `block lookup button` printed
|
|
9
|
+
* the global Button AND Launchpad's, concatenated, with nothing saying why
|
|
10
|
+
* there were two. The `tier` config key that was supposed to narrow this was
|
|
11
|
+
* read by nothing. So a read of a tiered noun now has a SCOPE, and the scope is
|
|
12
|
+
* part of the query rather than a predicate over what the query returned.
|
|
13
|
+
*
|
|
14
|
+
* THE RULE, in one place:
|
|
15
|
+
*
|
|
16
|
+
* - DEFAULT — the top-level tiers. A tier is top-level when its path-shaped
|
|
17
|
+
* name has no `/` (see {@link PackTierScope.by}): nothing sits above it.
|
|
18
|
+
* - A CHOSEN tier (`--tier apps_lxd`, or `tier: "apps_lxd"` in config) — that
|
|
19
|
+
* tier, its ancestors, and the declared base tier. `apps_lxd` therefore
|
|
20
|
+
* answers from `global`, `apps` and `apps_lxd`: the blocks an LXD screen is
|
|
21
|
+
* actually built from, which is the chain the design system's own colophon
|
|
22
|
+
* describes ("a lower tier inherits and overrides the blocks of its
|
|
23
|
+
* ancestors").
|
|
24
|
+
* - `all` — no scope at all, the pre-scope behaviour, reachable per call
|
|
25
|
+
* (`--tier all`) or as a setting (`tier: "all"`).
|
|
26
|
+
*
|
|
27
|
+
* PRECEDENCE is the one every other per-call argument has: the flag beats the
|
|
28
|
+
* config, the config beats the default. A per-call `--tier` is not a second
|
|
29
|
+
* narrowing on top of a configured one — it REPLACES it, because a chain is not
|
|
30
|
+
* an intersection of chains and an agent that passes `--tier apps_lxd` on a
|
|
31
|
+
* machine configured to `apps_launchpad` means the first.
|
|
32
|
+
*
|
|
33
|
+
* THE HIERARCHY IS READ FROM THE STORE, ONCE. Nothing here enumerates a tier:
|
|
34
|
+
* the tiers, their names and therefore their parents are read from the pack the
|
|
35
|
+
* session booted, so a tier added upstream tomorrow is scoped correctly with no
|
|
36
|
+
* edit here. The read is memoized per store SESSION (not per process): a
|
|
37
|
+
* `sources update` on the long-lived MCP server invalidates the session, and the
|
|
38
|
+
* next read re-learns the hierarchy from the pack that replaced it.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
import { cliRecovery, PragmaError } from "../error/index.js";
|
|
42
|
+
import type { PragmaRuntime } from "../runtime/index.js";
|
|
43
|
+
import type { StoreSession } from "../runtime/types.js";
|
|
44
|
+
import { formatTerm } from "./sparql/escape.js";
|
|
45
|
+
import { runSelect } from "./sparql/runSelect.js";
|
|
46
|
+
import { EVERY_TIER, type PackTierScope, type StorySource } from "./types.js";
|
|
47
|
+
|
|
48
|
+
/** One tier, with the hierarchy its own name states. */
|
|
49
|
+
export interface TierNode {
|
|
50
|
+
/** The tier's IRI, as the query filter binds it. */
|
|
51
|
+
readonly iri: string;
|
|
52
|
+
/** The tier's path-shaped name (`"Apps/LXD"`). */
|
|
53
|
+
readonly name: string;
|
|
54
|
+
/**
|
|
55
|
+
* The IRI's local name (`"apps_lxd"`) — the spelling `block list`'s `Tier`
|
|
56
|
+
* column prints and `--tier` accepts, so the scope is reported in the words a
|
|
57
|
+
* reader can type straight back.
|
|
58
|
+
*/
|
|
59
|
+
readonly local: string;
|
|
60
|
+
/** How deep the name sits: `"Global"` is 1, `"Apps/LXD"` is 2. */
|
|
61
|
+
readonly depth: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The tier hierarchy one pack declares, as the scope reads it. */
|
|
65
|
+
export interface TierHierarchy {
|
|
66
|
+
/** Every tier the store knows, in the order the read returned them. */
|
|
67
|
+
readonly tiers: readonly TierNode[];
|
|
68
|
+
/** The declared base tier, when the pack declares one and the store has it. */
|
|
69
|
+
readonly base?: TierNode;
|
|
70
|
+
/** Every spelling a caller may address a tier by → that tier. */
|
|
71
|
+
readonly bySpelling: ReadonlyMap<string, TierNode>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The tiers a read answers from, or every tier. */
|
|
75
|
+
export type TierScope =
|
|
76
|
+
| { readonly kind: "all" }
|
|
77
|
+
| {
|
|
78
|
+
/** The scope is these tiers, in reporting order (base first, then shallowest). */
|
|
79
|
+
readonly kind: "tiers";
|
|
80
|
+
readonly tiers: readonly TierNode[];
|
|
81
|
+
/** The tier a caller (or their config) asked for, when one was asked for. */
|
|
82
|
+
readonly chosen?: TierNode;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Every tier read once per store session, per declaration.
|
|
87
|
+
*
|
|
88
|
+
* Keyed on the SESSION so the memo cannot outlive the pack it describes, and
|
|
89
|
+
* nested by declaration so the three nouns that declare the same hierarchy
|
|
90
|
+
* (`block`, `modifier`, `concept`) share ONE query rather than issuing three
|
|
91
|
+
* identical ones per invocation. A `WeakMap` because the session is the owner:
|
|
92
|
+
* when the runtime drops it, this drops with it.
|
|
93
|
+
*/
|
|
94
|
+
const SESSIONS = new WeakMap<
|
|
95
|
+
StoreSession,
|
|
96
|
+
Map<string, Promise<TierHierarchy>>
|
|
97
|
+
>();
|
|
98
|
+
|
|
99
|
+
/** The SELECT reading every tier and its path-shaped name. */
|
|
100
|
+
function hierarchyQuery(declaration: PackTierScope): string {
|
|
101
|
+
return [
|
|
102
|
+
"SELECT ?tier ?name WHERE {",
|
|
103
|
+
` ?tier a ${formatTerm(declaration.type)} .`,
|
|
104
|
+
` ?tier ${formatTerm(declaration.by)} ?name .`,
|
|
105
|
+
"}",
|
|
106
|
+
"ORDER BY ?name",
|
|
107
|
+
].join("\n");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Read (once per session) the tier hierarchy a declaration describes.
|
|
112
|
+
*
|
|
113
|
+
* @param rt - The runtime, for the store and the query facade.
|
|
114
|
+
* @param declaration - The noun's declared tier hierarchy.
|
|
115
|
+
* @param source - The story's provenance, for a query diagnosis.
|
|
116
|
+
* @returns The hierarchy, memoized for this store session.
|
|
117
|
+
*/
|
|
118
|
+
export async function readTierHierarchy(
|
|
119
|
+
rt: PragmaRuntime,
|
|
120
|
+
declaration: PackTierScope,
|
|
121
|
+
source: StorySource,
|
|
122
|
+
): Promise<TierHierarchy> {
|
|
123
|
+
const session = await rt.store.get();
|
|
124
|
+
const key = [
|
|
125
|
+
declaration.type,
|
|
126
|
+
declaration.via,
|
|
127
|
+
declaration.by,
|
|
128
|
+
declaration.base ?? "",
|
|
129
|
+
].join("|");
|
|
130
|
+
let perDeclaration = SESSIONS.get(session);
|
|
131
|
+
if (!perDeclaration) {
|
|
132
|
+
perDeclaration = new Map();
|
|
133
|
+
SESSIONS.set(session, perDeclaration);
|
|
134
|
+
}
|
|
135
|
+
const memoized = perDeclaration.get(key);
|
|
136
|
+
if (memoized) return memoized;
|
|
137
|
+
const reading = runSelect(rt, hierarchyQuery(declaration), source).then(
|
|
138
|
+
(rows) =>
|
|
139
|
+
buildTierHierarchy(
|
|
140
|
+
rows.map((row) => ({ iri: row.tier ?? "", name: row.name ?? "" })),
|
|
141
|
+
declaration,
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
perDeclaration.set(key, reading);
|
|
145
|
+
return reading;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The local name of a term: everything after its last `#`, `/` or `:`.
|
|
150
|
+
*
|
|
151
|
+
* The `:` is what makes one function serve both spellings a term arrives in. A
|
|
152
|
+
* tier read out of the store is an absolute IRI
|
|
153
|
+
* (`https://ds.canonical.com/global`), and the declared `base` beside it is a
|
|
154
|
+
* PREFIXED name (`ds:global`) — the grammar admits either, everywhere. Reading
|
|
155
|
+
* only `#` and `/` left `ds:global` as its own local name, so the base tier
|
|
156
|
+
* matched nothing and the base-first reporting order silently became
|
|
157
|
+
* alphabetical.
|
|
158
|
+
*/
|
|
159
|
+
export function localName(term: string): string {
|
|
160
|
+
return term.replace(/^.*[#/:]/, "");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Every spelling of a tier a caller may type.
|
|
165
|
+
*
|
|
166
|
+
* Three, because three are in circulation and all of them are the reader's own
|
|
167
|
+
* words: the local name the `Tier` column prints (`apps_lxd`), the display name
|
|
168
|
+
* `tier list` prints (`Apps/LXD`), and that display name with its separator
|
|
169
|
+
* written the way the IRI writes it (`apps/lxd` — the spelling the config key's
|
|
170
|
+
* own documentation used before anything read it). Refusing two of the three
|
|
171
|
+
* would be refusing a value this distribution itself published.
|
|
172
|
+
*/
|
|
173
|
+
function spellings(tier: TierNode): string[] {
|
|
174
|
+
return [
|
|
175
|
+
tier.local.toLowerCase(),
|
|
176
|
+
tier.name.toLowerCase(),
|
|
177
|
+
tier.name.toLowerCase().replaceAll("/", "_"),
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Build the hierarchy from the rows the store returned.
|
|
183
|
+
*
|
|
184
|
+
* Exported for the unit tests, which state the hierarchy rules over a handful
|
|
185
|
+
* of rows rather than over the shipped pack's fifteen tiers.
|
|
186
|
+
*
|
|
187
|
+
* @param rows - One `{ iri, name }` per tier.
|
|
188
|
+
* @param declaration - The noun's declared tier hierarchy.
|
|
189
|
+
* @returns The hierarchy, with tiers carrying an empty IRI or name dropped —
|
|
190
|
+
* a tier the scope cannot address or place is not a tier it can scope by.
|
|
191
|
+
*/
|
|
192
|
+
export function buildTierHierarchy(
|
|
193
|
+
rows: readonly { readonly iri: string; readonly name: string }[],
|
|
194
|
+
declaration: PackTierScope,
|
|
195
|
+
): TierHierarchy {
|
|
196
|
+
const tiers: TierNode[] = [];
|
|
197
|
+
for (const row of rows) {
|
|
198
|
+
if (row.iri === "" || row.name === "") continue;
|
|
199
|
+
tiers.push({
|
|
200
|
+
iri: row.iri,
|
|
201
|
+
name: row.name,
|
|
202
|
+
local: localName(row.iri),
|
|
203
|
+
depth: row.name.split("/").length,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const bySpelling = new Map<string, TierNode>();
|
|
207
|
+
for (const tier of tiers) {
|
|
208
|
+
for (const spelling of spellings(tier)) {
|
|
209
|
+
if (!bySpelling.has(spelling)) bySpelling.set(spelling, tier);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const declaredBase = declaration.base;
|
|
213
|
+
const base =
|
|
214
|
+
declaredBase === undefined
|
|
215
|
+
? undefined
|
|
216
|
+
: tiers.find(
|
|
217
|
+
(tier) =>
|
|
218
|
+
tier.iri === declaredBase ||
|
|
219
|
+
tier.local.toLowerCase() === localName(declaredBase).toLowerCase(),
|
|
220
|
+
);
|
|
221
|
+
return { tiers, bySpelling, ...(base ? { base } : {}) };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* The reporting order: the base tier first, then shallowest first, then
|
|
226
|
+
* alphabetical.
|
|
227
|
+
*
|
|
228
|
+
* The base leads because it is what the rest inherit from, and the chain then
|
|
229
|
+
* reads root-to-leaf (`global, apps, apps_lxd`) — the direction the hierarchy
|
|
230
|
+
* is written in everywhere else in this distribution.
|
|
231
|
+
*/
|
|
232
|
+
function orderTiers(
|
|
233
|
+
tiers: readonly TierNode[],
|
|
234
|
+
base: TierNode | undefined,
|
|
235
|
+
): TierNode[] {
|
|
236
|
+
return [...tiers].sort((left, right) => {
|
|
237
|
+
if (left.iri === right.iri) return 0;
|
|
238
|
+
if (base) {
|
|
239
|
+
if (left.iri === base.iri) return -1;
|
|
240
|
+
if (right.iri === base.iri) return 1;
|
|
241
|
+
}
|
|
242
|
+
return (
|
|
243
|
+
left.depth - right.depth ||
|
|
244
|
+
left.local.localeCompare(right.local) ||
|
|
245
|
+
left.iri.localeCompare(right.iri)
|
|
246
|
+
);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** The tiers whose name states no parent — the default scope. */
|
|
251
|
+
function topLevel(hierarchy: TierHierarchy): TierNode[] {
|
|
252
|
+
return hierarchy.tiers.filter((tier) => tier.depth === 1);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The chosen tier's chain: itself, every tier its name sits under, and the base.
|
|
257
|
+
*
|
|
258
|
+
* An ancestor is found by NAME, not by an edge, because the graph asserts no
|
|
259
|
+
* edge (see {@link PackTierScope}). A name segment naming no declared tier
|
|
260
|
+
* contributes nothing — an orphan `Apps/LXD` in a pack with no `Apps` is
|
|
261
|
+
* scoped to itself and the base, which is the honest reading of the only
|
|
262
|
+
* hierarchy it states.
|
|
263
|
+
*/
|
|
264
|
+
function chain(hierarchy: TierHierarchy, chosen: TierNode): TierNode[] {
|
|
265
|
+
const segments = chosen.name.split("/");
|
|
266
|
+
const ancestorNames = new Set(
|
|
267
|
+
segments.slice(0, -1).map((_, index) =>
|
|
268
|
+
segments
|
|
269
|
+
.slice(0, index + 1)
|
|
270
|
+
.join("/")
|
|
271
|
+
.toLowerCase(),
|
|
272
|
+
),
|
|
273
|
+
);
|
|
274
|
+
const selected = hierarchy.tiers.filter(
|
|
275
|
+
(tier) =>
|
|
276
|
+
tier.iri === chosen.iri ||
|
|
277
|
+
ancestorNames.has(tier.name.toLowerCase()) ||
|
|
278
|
+
(hierarchy.base !== undefined && tier.iri === hierarchy.base.iri),
|
|
279
|
+
);
|
|
280
|
+
return orderTiers(selected, hierarchy.base);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** What a caller and their config asked of the scope for one read. */
|
|
284
|
+
export interface TierRequest {
|
|
285
|
+
/** The per-call `--tier` argument (`tier` over MCP), when one was passed. */
|
|
286
|
+
readonly requested?: unknown;
|
|
287
|
+
/** The `tier` config key, when it is set. */
|
|
288
|
+
readonly configured?: string;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Resolve the scope one read answers under.
|
|
293
|
+
*
|
|
294
|
+
* @param hierarchy - The tiers the store knows.
|
|
295
|
+
* @param request - The per-call argument and the configured default.
|
|
296
|
+
* @returns Every tier (when asked for, or when the store knows no tiers), else
|
|
297
|
+
* the chosen tier's chain, else the top-level tiers.
|
|
298
|
+
* @throws PragmaError INVALID_INPUT when a tier was asked for by a name no tier
|
|
299
|
+
* answers to, carrying the names that do.
|
|
300
|
+
*/
|
|
301
|
+
export function resolveTierScope(
|
|
302
|
+
hierarchy: TierHierarchy,
|
|
303
|
+
request: TierRequest,
|
|
304
|
+
): TierScope {
|
|
305
|
+
// A graph with no tiers in it is not a narrowed graph: there is nothing to
|
|
306
|
+
// scope by, so the read answers as it always did and says nothing about a
|
|
307
|
+
// scope it never applied.
|
|
308
|
+
if (hierarchy.tiers.length === 0) return { kind: "all" };
|
|
309
|
+
const perCall = readRequested(request.requested);
|
|
310
|
+
const asked = perCall ?? request.configured?.trim();
|
|
311
|
+
if (asked === undefined || asked === "") {
|
|
312
|
+
return {
|
|
313
|
+
kind: "tiers",
|
|
314
|
+
tiers: orderTiers(topLevel(hierarchy), hierarchy.base),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
if (asked.toLowerCase() === EVERY_TIER) return { kind: "all" };
|
|
318
|
+
const chosen = hierarchy.bySpelling.get(asked.toLowerCase());
|
|
319
|
+
if (!chosen) {
|
|
320
|
+
const validOptions = [
|
|
321
|
+
EVERY_TIER,
|
|
322
|
+
...hierarchy.tiers.map((tier) => tier.local).sort(),
|
|
323
|
+
];
|
|
324
|
+
// The recovery names WHERE the bad value came from, because the two places
|
|
325
|
+
// are fixed differently and only one of them is in the caller's hand: a
|
|
326
|
+
// per-call `--tier` is retyped, a configured one is unset. A reader whose
|
|
327
|
+
// machine is set to a tier this pack does not carry would otherwise be told
|
|
328
|
+
// to retype an argument they never typed.
|
|
329
|
+
throw PragmaError.invalidInput("tier", asked, {
|
|
330
|
+
validOptions,
|
|
331
|
+
recovery:
|
|
332
|
+
perCall === undefined
|
|
333
|
+
? cliRecovery(
|
|
334
|
+
"config unset tier",
|
|
335
|
+
`The \`tier\` config key names "${asked}", which is not one of this pack's ${hierarchy.tiers.length} tiers. Clear it, or set one that exists.`,
|
|
336
|
+
{ tool: "config_unset", params: { key: "tier" } },
|
|
337
|
+
)
|
|
338
|
+
: cliRecovery(
|
|
339
|
+
"tier list",
|
|
340
|
+
`Name one of the ${hierarchy.tiers.length} tiers, or "${EVERY_TIER}" for every tier.`,
|
|
341
|
+
{ tool: "tier_list", params: {} },
|
|
342
|
+
),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return { kind: "tiers", tiers: chain(hierarchy, chosen), chosen };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* The per-call argument as a tier name.
|
|
350
|
+
*
|
|
351
|
+
* @throws PragmaError INVALID_INPUT when it is not a string — a repeated
|
|
352
|
+
* `--tier` is a caller asking for two chains at once, which is not a chain.
|
|
353
|
+
*/
|
|
354
|
+
function readRequested(provided: unknown): string | undefined {
|
|
355
|
+
if (provided === undefined) return undefined;
|
|
356
|
+
if (typeof provided === "string") {
|
|
357
|
+
const trimmed = provided.trim();
|
|
358
|
+
return trimmed === "" ? undefined : trimmed;
|
|
359
|
+
}
|
|
360
|
+
throw PragmaError.invalidInput("tier", String(provided), {
|
|
361
|
+
recovery: {
|
|
362
|
+
message: `Pass one tier name, or "${EVERY_TIER}" for every tier.`,
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* The scope one read of a tiered noun answers under, resolved from everything
|
|
369
|
+
* that has a say: the story's declaration, the caller's argument, the config.
|
|
370
|
+
*
|
|
371
|
+
* @param rt - The runtime (store for the hierarchy, config for the default).
|
|
372
|
+
* @param declaration - The noun's declared hierarchy, absent when it is not
|
|
373
|
+
* tiered — in which case there is no scope and nothing is read.
|
|
374
|
+
* @param requested - The per-call `--tier` argument, if any.
|
|
375
|
+
* @param source - The story's provenance, for a query diagnosis.
|
|
376
|
+
* @returns The scope, or `undefined` for an unscoped noun.
|
|
377
|
+
* @throws PragmaError INVALID_INPUT when the tier asked for does not exist.
|
|
378
|
+
*/
|
|
379
|
+
export async function resolveReadScope(
|
|
380
|
+
rt: PragmaRuntime,
|
|
381
|
+
declaration: PackTierScope | undefined,
|
|
382
|
+
requested: unknown,
|
|
383
|
+
source: StorySource,
|
|
384
|
+
): Promise<TierScope | undefined> {
|
|
385
|
+
if (!declaration) return undefined;
|
|
386
|
+
const hierarchy = await readTierHierarchy(rt, declaration, source);
|
|
387
|
+
const { config } = await rt.loadConfig();
|
|
388
|
+
return resolveTierScope(hierarchy, {
|
|
389
|
+
requested,
|
|
390
|
+
...(config.tier === undefined ? {} : { configured: config.tier }),
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* The scope in the words a reader can type back: `global, apps, apps_lxd`.
|
|
396
|
+
*
|
|
397
|
+
* @param scope - The resolved scope.
|
|
398
|
+
* @returns The in-scope tier local names, or `undefined` for every tier — a
|
|
399
|
+
* read that narrowed nothing has no scope to report.
|
|
400
|
+
*/
|
|
401
|
+
export function scopeLabel(scope: TierScope): string | undefined {
|
|
402
|
+
if (scope.kind === "all") return undefined;
|
|
403
|
+
return scope.tiers.map((tier) => tier.local).join(", ");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** The in-scope tier IRIs, for the query filter. */
|
|
407
|
+
export function scopeIris(scope: TierScope): readonly string[] {
|
|
408
|
+
return scope.kind === "all" ? [] : scope.tiers.map((tier) => tier.iri);
|
|
409
|
+
}
|
|
@@ -36,6 +36,13 @@ const verb = (
|
|
|
36
36
|
return found;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
// The fragments below track the stories' CURRENT prose. They are quoted by
|
|
40
|
+
// FRAGMENT and not by exact string on purpose — tool descriptions are
|
|
41
|
+
// explicitly not frozen, and what this file pins is the WIRING: that a
|
|
42
|
+
// definition-level description reaches the list tool, a lookup-level one
|
|
43
|
+
// reaches the lookup tool, an extra verb's reaches its own, and that the MCP
|
|
44
|
+
// call example never leaks into CLI help. When a story's prose is rewritten
|
|
45
|
+
// these move with it; when a description stops REACHING its tool, they fail.
|
|
39
46
|
describe("pack toolDescription wiring (PROTECTED)", () => {
|
|
40
47
|
it("routes the lookup-level toolDescription to MCP, whole (with the call example)", async () => {
|
|
41
48
|
const mcp = await projectMcp([tokenModule]);
|
|
@@ -43,11 +50,9 @@ describe("pack toolDescription wiring (PROTECTED)", () => {
|
|
|
43
50
|
(t) => t.name === "token_lookup",
|
|
44
51
|
)?.description;
|
|
45
52
|
await mcp.cleanup();
|
|
46
|
-
expect(desc).toContain(
|
|
47
|
-
"Get type and theme values for one or more design tokens by name.",
|
|
48
|
-
);
|
|
53
|
+
expect(desc).toContain("Get one design-token symbol in full");
|
|
49
54
|
// The authored MCP tool-call example survives on the MCP surface.
|
|
50
|
-
expect(desc).toContain('Example: token_lookup { name: ["color.
|
|
55
|
+
expect(desc).toContain('Example: token_lookup { name: ["color.text"] }');
|
|
51
56
|
});
|
|
52
57
|
|
|
53
58
|
it("routes the definition-level toolDescription to the MCP list tool", async () => {
|
|
@@ -58,8 +63,8 @@ describe("pack toolDescription wiring (PROTECTED)", () => {
|
|
|
58
63
|
await mcp.cleanup();
|
|
59
64
|
// The rich description reaches MCP (was previously dropped — only `summary`
|
|
60
65
|
// reached the tool), including the authored call example.
|
|
61
|
-
expect(desc).toContain("List
|
|
62
|
-
expect(desc).toContain(
|
|
66
|
+
expect(desc).toContain("List the design-token SYMBOLS");
|
|
67
|
+
expect(desc).toContain('Example: token_list { type: "color" }');
|
|
63
68
|
});
|
|
64
69
|
|
|
65
70
|
it("routes an extra-verb toolDescription to its MCP tool", async () => {
|
|
@@ -77,15 +82,13 @@ describe("pack toolDescription wiring (PROTECTED)", () => {
|
|
|
77
82
|
|
|
78
83
|
it("CLI --help shows the rich prose but NEVER the MCP tool-call syntax", () => {
|
|
79
84
|
const lookupHelp = formatVerbHelp("pragma", verb(tokenModule, "lookup"));
|
|
80
|
-
expect(lookupHelp).toContain(
|
|
81
|
-
"Get type and theme values for one or more design tokens by name.",
|
|
82
|
-
);
|
|
85
|
+
expect(lookupHelp).toContain("Get one design-token symbol in full");
|
|
83
86
|
// No-leaks: the `token_lookup {…}` MCP call shape must not reach CLI help.
|
|
84
87
|
expect(lookupHelp).not.toContain("token_lookup {");
|
|
85
88
|
expect(lookupHelp).not.toContain("Example:");
|
|
86
89
|
|
|
87
90
|
const listHelp = formatVerbHelp("pragma", verb(tokenModule, "list"));
|
|
88
|
-
expect(listHelp).toContain("List
|
|
91
|
+
expect(listHelp).toContain("List the design-token SYMBOLS");
|
|
89
92
|
expect(listHelp).not.toContain("token_list {");
|
|
90
93
|
});
|
|
91
94
|
});
|