@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
|
@@ -71,6 +71,11 @@ export const TOOL_HINTS: Record<string, ToolHint> = {
|
|
|
71
71
|
use_when:
|
|
72
72
|
"Checking the active configuration (tier, channel, detail) and which layer set each field",
|
|
73
73
|
},
|
|
74
|
+
graph_connect: {
|
|
75
|
+
category: "read",
|
|
76
|
+
use_when:
|
|
77
|
+
"Deciding whether two entities are related at all — the shortest relation paths between them, or which kind of nothing there is",
|
|
78
|
+
},
|
|
74
79
|
graph_inspect: {
|
|
75
80
|
category: "read",
|
|
76
81
|
use_when:
|
|
@@ -168,7 +173,7 @@ export const TOOL_HINTS: Record<string, ToolHint> = {
|
|
|
168
173
|
},
|
|
169
174
|
tier_list: {
|
|
170
175
|
category: "read",
|
|
171
|
-
use_when: "
|
|
176
|
+
use_when: "Picking the tier to scope a read to (the `tier` parameter)",
|
|
172
177
|
},
|
|
173
178
|
tier_lookup: {
|
|
174
179
|
category: "read",
|
|
@@ -177,17 +182,47 @@ export const TOOL_HINTS: Record<string, ToolHint> = {
|
|
|
177
182
|
token_list: {
|
|
178
183
|
category: "read",
|
|
179
184
|
use_when:
|
|
180
|
-
"Browsing
|
|
185
|
+
"Browsing which token SYMBOLS exist (the logical dotted names), optionally by type or by the symbol a channel provisions",
|
|
181
186
|
},
|
|
182
187
|
token_lookup: {
|
|
183
188
|
category: "read",
|
|
184
189
|
use_when:
|
|
185
|
-
"Need
|
|
190
|
+
"Need one symbol in full — its definitions, the families that may rebind it, and what it resolves to at each position",
|
|
191
|
+
},
|
|
192
|
+
token_values: {
|
|
193
|
+
category: "read",
|
|
194
|
+
use_when:
|
|
195
|
+
"Need the value a symbol resolves to at a position, with the chain that produced it or the symbol it derives from",
|
|
196
|
+
},
|
|
197
|
+
token_consumers: {
|
|
198
|
+
category: "read",
|
|
199
|
+
use_when:
|
|
200
|
+
"Need which blocks consume a symbol, at which style key, state and rank",
|
|
186
201
|
},
|
|
187
202
|
token_sample: {
|
|
188
203
|
category: "read",
|
|
189
204
|
use_when:
|
|
190
|
-
"See actual token data shapes
|
|
205
|
+
"See actual token symbol data shapes before querying — returns random instances each call",
|
|
206
|
+
},
|
|
207
|
+
variable_list: {
|
|
208
|
+
category: "read",
|
|
209
|
+
use_when:
|
|
210
|
+
"Browsing the platform names a stylesheet declares, by platform, symbol, tier, visibility or coordinate — including the 236 that stand for no symbol",
|
|
211
|
+
},
|
|
212
|
+
variable_lookup: {
|
|
213
|
+
category: "read",
|
|
214
|
+
use_when:
|
|
215
|
+
"Need one platform variable in full — its symbol, tier, visibility, and every selector and at-rule it is declared under",
|
|
216
|
+
},
|
|
217
|
+
variable_chain: {
|
|
218
|
+
category: "read",
|
|
219
|
+
use_when:
|
|
220
|
+
"Need what a variable finally means: the transitive walk to every symbol it reaches",
|
|
221
|
+
},
|
|
222
|
+
variable_sample: {
|
|
223
|
+
category: "read",
|
|
224
|
+
use_when:
|
|
225
|
+
"See actual platform variable data shapes before querying — returns random instances each call",
|
|
191
226
|
},
|
|
192
227
|
|
|
193
228
|
// — Write ——————————————————————————————————————————————————————————————————
|
|
@@ -213,7 +248,7 @@ export const TOOL_HINTS: Record<string, ToolHint> = {
|
|
|
213
248
|
create_application: {
|
|
214
249
|
category: "write",
|
|
215
250
|
use_when:
|
|
216
|
-
"Scaffolding a new React application with
|
|
251
|
+
"Scaffolding a new React application with routing, optional Relay, and either server-side rendering or a client-only SPA",
|
|
217
252
|
},
|
|
218
253
|
setup: {
|
|
219
254
|
category: "write",
|
|
@@ -108,36 +108,35 @@ describe("config set — the reserved clear-markers are refused, naming unset",
|
|
|
108
108
|
// Clearing a field is a command, so no value may quietly mean "remove me":
|
|
109
109
|
// the three strings that used to are rejected, and the rejection names the
|
|
110
110
|
// command that owns the job. `tier` keeps whatever it held.
|
|
111
|
-
it.each([
|
|
112
|
-
"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
])("set tier %s is INVALID_INPUT that recovers with config unset tier", async (reserved) => {
|
|
116
|
-
const cwd = tmp("pragma-proj-");
|
|
117
|
-
await executeVerb(
|
|
118
|
-
setVerb,
|
|
119
|
-
{ key: "tier", value: "apps/lxd" },
|
|
120
|
-
REAL,
|
|
121
|
-
bootRuntime(FLAGS, cwd),
|
|
122
|
-
);
|
|
123
|
-
let caught: unknown;
|
|
124
|
-
try {
|
|
111
|
+
it.each(["none", "default", "-"])(
|
|
112
|
+
"set tier %s is INVALID_INPUT that recovers with config unset tier",
|
|
113
|
+
async (reserved) => {
|
|
114
|
+
const cwd = tmp("pragma-proj-");
|
|
125
115
|
await executeVerb(
|
|
126
116
|
setVerb,
|
|
127
|
-
{ key: "tier", value:
|
|
117
|
+
{ key: "tier", value: "apps/lxd" },
|
|
128
118
|
REAL,
|
|
129
119
|
bootRuntime(FLAGS, cwd),
|
|
130
120
|
);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
121
|
+
let caught: unknown;
|
|
122
|
+
try {
|
|
123
|
+
await executeVerb(
|
|
124
|
+
setVerb,
|
|
125
|
+
{ key: "tier", value: reserved },
|
|
126
|
+
REAL,
|
|
127
|
+
bootRuntime(FLAGS, cwd),
|
|
128
|
+
);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
caught = error;
|
|
131
|
+
}
|
|
132
|
+
expect(caught).toBeInstanceOf(PragmaError);
|
|
133
|
+
expect((caught as PragmaError).code).toBe("INVALID_INPUT");
|
|
134
|
+
expect(JSON.stringify((caught as PragmaError).recovery)).toContain(
|
|
135
|
+
"config unset tier",
|
|
136
|
+
);
|
|
137
|
+
expect(readGlobal().tier).toBe("apps/lxd");
|
|
138
|
+
},
|
|
139
|
+
);
|
|
141
140
|
|
|
142
141
|
it("a reserved marker is only reserved for a free-string field", () => {
|
|
143
142
|
// `channel`/`detail` are closed enums: their rejection is the enum
|
|
@@ -40,7 +40,9 @@ describe("renderConfigShowPlain", () => {
|
|
|
40
40
|
it("is byte-identical to the plain form when the styler is disabled", () => {
|
|
41
41
|
expect(renderConfigShowPlain(DATA, styleFor(false))).toBe(
|
|
42
42
|
[
|
|
43
|
-
|
|
43
|
+
// The value AND the scope it puts every tiered read under: `tier`
|
|
44
|
+
// decides a scope now, so the line that reports it says which.
|
|
45
|
+
"tier: apps/lxd — apps/lxd and its ancestors [project]",
|
|
44
46
|
"channel: normal",
|
|
45
47
|
"detail: standard",
|
|
46
48
|
"packs: @canonical/ds [global]",
|
|
@@ -55,7 +57,7 @@ describe("renderConfigShowPlain", () => {
|
|
|
55
57
|
const keyWidth = "project config:".length;
|
|
56
58
|
// Dim, padded key; cyan value; dim `[layer]` marker.
|
|
57
59
|
expect(out).toContain(
|
|
58
|
-
`<d>${"tier:".padEnd(keyWidth)}</d> <c>apps/lxd</c><d> [project]</d>`,
|
|
60
|
+
`<d>${"tier:".padEnd(keyWidth)}</d> <c>apps/lxd — apps/lxd and its ancestors</c><d> [project]</d>`,
|
|
59
61
|
);
|
|
60
62
|
// A default-origin value carries no marker.
|
|
61
63
|
expect(out).toContain(
|
|
@@ -82,7 +84,8 @@ describe("renderConfigShowPlain", () => {
|
|
|
82
84
|
|
|
83
85
|
const out = renderConfigShowPlain(bare, styleFor(false));
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
// Unset is not "no scope": it is the default scope, and the line says so.
|
|
88
|
+
expect(out).toContain("tier: (none) — the top-level tiers");
|
|
86
89
|
expect(out).toContain("packs: (none)");
|
|
87
90
|
expect(out).toContain("project config: (not found)");
|
|
88
91
|
});
|
|
@@ -92,7 +95,9 @@ describe("configShowFormatters.llm", () => {
|
|
|
92
95
|
it("renders the layered rows with origin markers", () => {
|
|
93
96
|
const out = configShowFormatters.llm(DATA);
|
|
94
97
|
|
|
95
|
-
expect(out).toContain(
|
|
98
|
+
expect(out).toContain(
|
|
99
|
+
"- **Tier:** apps/lxd — apps/lxd and its ancestors [project]",
|
|
100
|
+
);
|
|
96
101
|
expect(out).toContain("- **Packs:** @canonical/ds [global]");
|
|
97
102
|
});
|
|
98
103
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { ConfigOrigin } from "../../kernel/config/types.js";
|
|
10
|
+
import { EVERY_TIER } from "../../kernel/packs/types.js";
|
|
10
11
|
import { defaultStyle, type RenderStyle } from "../../kernel/render/style.js";
|
|
11
12
|
import type { Formatters } from "../../kernel/spec/index.js";
|
|
12
13
|
import type { ConfigShowData } from "./types.js";
|
|
@@ -16,6 +17,29 @@ function originMarker(origin: ConfigOrigin): string {
|
|
|
16
17
|
return origin === "default" ? "" : ` [${origin}]`;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The `tier` value with the SCOPE it puts every tiered read under.
|
|
22
|
+
*
|
|
23
|
+
* The value alone is not the answer to "what am I reading". `tier` used to be
|
|
24
|
+
* accepted and read by nothing, and `config show` reported it as a setting in
|
|
25
|
+
* force while `block list` answered from all fifteen tiers; now it decides a
|
|
26
|
+
* scope, so this line has to say which. The three cases are the whole rule:
|
|
27
|
+
* unset is the top-level tiers, a tier is that tier and its ancestors, and
|
|
28
|
+
* `all` turns the scope off.
|
|
29
|
+
*
|
|
30
|
+
* It names the RULE and not the tiers, deliberately: `config show` is storeless
|
|
31
|
+
* (`capability.needsStore: false`) and naming the five top-level tiers means
|
|
32
|
+
* booting the pack to read them. The tiers themselves are one command away
|
|
33
|
+
* (`tier list`), and every scoped answer states its own scope in its heading —
|
|
34
|
+
* so the reading a store could add here is already available where it matters.
|
|
35
|
+
*/
|
|
36
|
+
function tierScope(tier: string | undefined): string {
|
|
37
|
+
if (tier === undefined) return "the top-level tiers";
|
|
38
|
+
return tier.trim().toLowerCase() === EVERY_TIER
|
|
39
|
+
? "every tier"
|
|
40
|
+
: `${tier} and its ancestors`;
|
|
41
|
+
}
|
|
42
|
+
|
|
19
43
|
/** Summarize a list of named entries as a comma-separated set of names. */
|
|
20
44
|
function entryNames(entries: readonly (string | { name: string })[]): string {
|
|
21
45
|
const names = entries.map((entry) =>
|
|
@@ -31,7 +55,11 @@ type ConfigRow = readonly [label: string, value: string, marker: string];
|
|
|
31
55
|
function configRows(data: ConfigShowData): readonly ConfigRow[] {
|
|
32
56
|
const { config, origins } = data;
|
|
33
57
|
return [
|
|
34
|
-
[
|
|
58
|
+
[
|
|
59
|
+
"tier",
|
|
60
|
+
`${config.tier ?? "(none)"} — ${tierScope(config.tier)}`,
|
|
61
|
+
originMarker(origins.tier),
|
|
62
|
+
],
|
|
35
63
|
["channel", config.channel, originMarker(origins.channel)],
|
|
36
64
|
["detail", config.detail ?? "standard", originMarker(origins.detail)],
|
|
37
65
|
["packs", entryNames(config.packs ?? []), originMarker(origins.packs)],
|
|
@@ -84,7 +112,7 @@ export const configShowFormatters: Formatters<ConfigShowData> = {
|
|
|
84
112
|
const lines = [
|
|
85
113
|
"## Configuration",
|
|
86
114
|
"",
|
|
87
|
-
`- **Tier:** ${config.tier ?? "none"}${originMarker(origins.tier)}`,
|
|
115
|
+
`- **Tier:** ${config.tier ?? "none"} — ${tierScope(config.tier)}${originMarker(origins.tier)}`,
|
|
88
116
|
`- **Channel:** ${config.channel}${originMarker(origins.channel)}`,
|
|
89
117
|
`- **Detail:** ${config.detail ?? "standard"}${originMarker(origins.detail)}`,
|
|
90
118
|
`- **Packs:** ${entryNames(config.packs ?? [])}${originMarker(origins.packs)}`,
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* `create` verbs take. No new package edge: pragma already depends on
|
|
16
16
|
* summon-core, and never on the summon bin.
|
|
17
17
|
*
|
|
18
|
-
* Five generators are covered: component × {react, svelte, lit},
|
|
18
|
+
* Five generators are covered across seven fixtures: component × {react, svelte, lit},
|
|
19
|
+
* package, and
|
|
19
20
|
* application. A cross-binary subprocess guard lives in byteEquality.subprocess.test.ts.
|
|
20
21
|
*/
|
|
21
22
|
|
|
@@ -175,6 +176,32 @@ const cases: Case[] = [
|
|
|
175
176
|
runInstall: false,
|
|
176
177
|
},
|
|
177
178
|
},
|
|
179
|
+
{
|
|
180
|
+
fixture: "application-spa",
|
|
181
|
+
kind: "application",
|
|
182
|
+
framework: "",
|
|
183
|
+
params: {
|
|
184
|
+
appPath: "my-app",
|
|
185
|
+
forms: true,
|
|
186
|
+
intl: false,
|
|
187
|
+
relay: false,
|
|
188
|
+
rendering: "spa",
|
|
189
|
+
runInstall: false,
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
fixture: "application-spa-all",
|
|
194
|
+
kind: "application",
|
|
195
|
+
framework: "",
|
|
196
|
+
params: {
|
|
197
|
+
appPath: "my-app",
|
|
198
|
+
forms: true,
|
|
199
|
+
intl: true,
|
|
200
|
+
relay: true,
|
|
201
|
+
rendering: "spa",
|
|
202
|
+
runInstall: false,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
178
205
|
];
|
|
179
206
|
|
|
180
207
|
describe("byte-equality goldens — pragma create \u2261 the conformance reference (PROTECTED)", () => {
|
|
@@ -523,11 +523,12 @@ export const createVerbs: Record<
|
|
|
523
523
|
),
|
|
524
524
|
application: createVerb(
|
|
525
525
|
"application",
|
|
526
|
-
"Scaffold a full React application with
|
|
526
|
+
"Scaffold a full React application with routing, and either server-side rendering or a client-only SPA.",
|
|
527
527
|
applicationParams,
|
|
528
528
|
[
|
|
529
529
|
{ cmd: `${BIN_NAME} create application react my-app` },
|
|
530
530
|
{ cmd: `${BIN_NAME} create application react my-app --relay` },
|
|
531
|
+
{ cmd: `${BIN_NAME} create application react my-app --rendering spa` },
|
|
531
532
|
],
|
|
532
533
|
),
|
|
533
534
|
};
|
|
@@ -655,7 +655,10 @@ describe("the mounted create grammar (subprocess)", () => {
|
|
|
655
655
|
"--type": "library",
|
|
656
656
|
"--description": "A replied library.",
|
|
657
657
|
},
|
|
658
|
-
"application/react": {
|
|
658
|
+
"application/react": {
|
|
659
|
+
"--app-path": "replied-app",
|
|
660
|
+
"--rendering": "spa",
|
|
661
|
+
},
|
|
659
662
|
};
|
|
660
663
|
for (const [commandPath, surface] of Object.entries(CREATE_SURFACE)) {
|
|
661
664
|
it(`${commandPath}: the refusal's own instruction WORKS — its Missing tokens supplied back (+ --dry-run) preview, exit 0`, () => {
|
|
@@ -17,7 +17,7 @@ export const CREATE_SURFACE: Readonly<Record<string, SurfaceCommand>> = {
|
|
|
17
17
|
"application",
|
|
18
18
|
"react"
|
|
19
19
|
],
|
|
20
|
-
"description": "Scaffold a complete React application with
|
|
20
|
+
"description": "Scaffold a complete React application with routing, and either server-side rendering or a client-only SPA",
|
|
21
21
|
"prompts": [
|
|
22
22
|
{
|
|
23
23
|
"name": "appPath",
|
|
@@ -41,6 +41,23 @@ export const CREATE_SURFACE: Readonly<Record<string, SurfaceCommand>> = {
|
|
|
41
41
|
"default": false,
|
|
42
42
|
"group": "Application"
|
|
43
43
|
},
|
|
44
|
+
{
|
|
45
|
+
"name": "rendering",
|
|
46
|
+
"type": "select",
|
|
47
|
+
"message": "Rendering — ssr keeps the server layer (SSR servers and sitemap), spa is client-only",
|
|
48
|
+
"default": "ssr",
|
|
49
|
+
"choices": [
|
|
50
|
+
{
|
|
51
|
+
"label": "ssr - server-side rendering (Express + Bun servers, sitemap)",
|
|
52
|
+
"value": "ssr"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"label": "spa - client-only single-page app (no server layer)",
|
|
56
|
+
"value": "spa"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"group": "Application"
|
|
60
|
+
},
|
|
44
61
|
{
|
|
45
62
|
"name": "relay",
|
|
46
63
|
"type": "confirm",
|
|
@@ -278,6 +295,11 @@ export const CREATE_CLI_SYNTAX: Readonly<
|
|
|
278
295
|
"takesValue": false,
|
|
279
296
|
"kebabName": "intl"
|
|
280
297
|
},
|
|
298
|
+
"rendering": {
|
|
299
|
+
"flag": "--rendering",
|
|
300
|
+
"takesValue": true,
|
|
301
|
+
"kebabName": "rendering"
|
|
302
|
+
},
|
|
281
303
|
"relay": {
|
|
282
304
|
"flag": "--relay",
|
|
283
305
|
"takesValue": false,
|
|
@@ -258,9 +258,16 @@ describe("cross-CLI conformance matrix (PROTECTED)", () => {
|
|
|
258
258
|
// here, which is the point).
|
|
259
259
|
it("every declared generator binding path is driven by a conformance fixture", () => {
|
|
260
260
|
expect(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
261
|
+
// Deduplicated: the assertion is that every declared path is COVERED, and
|
|
262
|
+
// one path may carry several fixtures — application/react is driven by
|
|
263
|
+
// both the SSR arm and the SPA arm.
|
|
264
|
+
[
|
|
265
|
+
...new Set(
|
|
266
|
+
CONFORMANCE_FIXTURES.map((fixture) =>
|
|
267
|
+
commandPathOf(fixture.generator),
|
|
268
|
+
),
|
|
269
|
+
),
|
|
270
|
+
].sort(),
|
|
264
271
|
).toEqual(
|
|
265
272
|
Object.values(CREATE_GENERATORS)
|
|
266
273
|
.flatMap((binding) => binding.paths as readonly string[])
|
|
@@ -13,7 +13,7 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
|
13
13
|
import { compilePack } from "../kernel/packs/compile.js";
|
|
14
14
|
import type { LookupOutput } from "../kernel/packs/resolveEntity.js";
|
|
15
15
|
import { parsePackDefinition } from "../kernel/packs/schema.js";
|
|
16
|
-
import type {
|
|
16
|
+
import type { PackPage } from "../kernel/packs/types.js";
|
|
17
17
|
import { distributionSource } from "../kernel/packs/types.js";
|
|
18
18
|
import { verbKey } from "../kernel/packs/uniqueness.js";
|
|
19
19
|
import { DEFAULT_PREFIX_MAP } from "../kernel/render/prefixes.js";
|
|
@@ -122,7 +122,7 @@ describe("standard story definition (PROTECTED)", () => {
|
|
|
122
122
|
|
|
123
123
|
describe("standard list parity", () => {
|
|
124
124
|
it("lists every standard with the uniform row shape", async () => {
|
|
125
|
-
const rows = (await verb("list").run({}, rt)) as
|
|
125
|
+
const rows = ((await verb("list").run({}, rt)) as PackPage).rows;
|
|
126
126
|
expect(rows.map((r) => r.name)).toEqual([
|
|
127
127
|
"code/function/purity",
|
|
128
128
|
"react/component/props",
|
|
@@ -135,25 +135,26 @@ describe("standard list parity", () => {
|
|
|
135
135
|
});
|
|
136
136
|
|
|
137
137
|
it("filters by category and searches, conjunctively", async () => {
|
|
138
|
-
const react = (
|
|
139
|
-
{ category: "react" },
|
|
140
|
-
|
|
141
|
-
)) as PackRow[];
|
|
138
|
+
const react = (
|
|
139
|
+
(await verb("list").run({ category: "react" }, rt)) as PackPage
|
|
140
|
+
).rows;
|
|
142
141
|
expect(react.map((r) => r.name).sort()).toEqual([
|
|
143
142
|
"react/component/props",
|
|
144
143
|
"react/component/structure",
|
|
145
144
|
]);
|
|
146
|
-
const searched = (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
const searched = (
|
|
146
|
+
(await verb("list").run(
|
|
147
|
+
{ category: "react", search: "structure" },
|
|
148
|
+
rt,
|
|
149
|
+
)) as PackPage
|
|
150
|
+
).rows;
|
|
150
151
|
expect(searched.map((r) => r.name)).toEqual(["react/component/structure"]);
|
|
151
152
|
});
|
|
152
153
|
});
|
|
153
154
|
|
|
154
155
|
describe("standard categories parity", () => {
|
|
155
156
|
it("lists categories with their standard counts", async () => {
|
|
156
|
-
const rows = (await verb("categories").run({}, rt)) as
|
|
157
|
+
const rows = ((await verb("categories").run({}, rt)) as PackPage).rows;
|
|
157
158
|
const counts = new Map(rows.map((r) => [r.name, Number(r.count)]));
|
|
158
159
|
expect(counts.get("react")).toBe(2);
|
|
159
160
|
expect(counts.get("code")).toBe(1);
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { describe, expect, it } from "vitest";
|
|
15
15
|
import { compilePack } from "../kernel/packs/compile.js";
|
|
16
16
|
import { parsePackDefinition } from "../kernel/packs/schema.js";
|
|
17
|
+
import { storyIssues } from "../kernel/packs/storyRules.js";
|
|
17
18
|
import { DEFAULT_PREFIX_MAP } from "../kernel/render/prefixes.js";
|
|
18
19
|
import type { VerbSpec } from "../kernel/spec/types.js";
|
|
19
20
|
import { VOCABULARY } from "../kernel/vocabulary.js";
|
|
@@ -45,16 +46,85 @@ describe("the distribution's declared stories (PROTECTED)", () => {
|
|
|
45
46
|
"standard",
|
|
46
47
|
"tier",
|
|
47
48
|
"token",
|
|
49
|
+
"variable",
|
|
48
50
|
]);
|
|
49
51
|
});
|
|
50
52
|
|
|
51
|
-
it.each([
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
it.each([...declaredStories.keys()])(
|
|
54
|
+
"the %s story validates against the pack grammar, unchanged",
|
|
55
|
+
(noun) => {
|
|
56
|
+
const story = declaredStories.get(noun);
|
|
57
|
+
expect(
|
|
58
|
+
parsePackDefinition(
|
|
59
|
+
JSON.parse(JSON.stringify(story)),
|
|
60
|
+
"pragma.conf.ts",
|
|
61
|
+
),
|
|
62
|
+
).toEqual(story);
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
it('every declared filter names "values" or a "vocabulary"', () => {
|
|
67
|
+
// The rule the round-trip above already enforces, said OUT LOUD. It was
|
|
68
|
+
// only implied there — a story satisfies the whole grammar or it does not,
|
|
69
|
+
// and a reader looking for this particular property found no assertion
|
|
70
|
+
// claiming it. It is the property that separates a refusal (INVALID_INPUT
|
|
71
|
+
// naming the admissible values) from a calm empty page, so it is worth a
|
|
72
|
+
// test that fails with the rule's own name on it.
|
|
73
|
+
const filters = [...declaredStories].flatMap(([noun, story]) => [
|
|
74
|
+
...(story.list?.filters ?? []).map(
|
|
75
|
+
(filter) => [`${noun} list --${filter.param}`, filter] as const,
|
|
76
|
+
),
|
|
77
|
+
...(story.verbs ?? []).flatMap((verb) =>
|
|
78
|
+
(verb.filters ?? []).map(
|
|
79
|
+
(filter) =>
|
|
80
|
+
[`${noun} ${verb.verb} --${filter.param}`, filter] as const,
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
]);
|
|
84
|
+
// A guard, not a no-op: an empty derivation would make this vacuous.
|
|
85
|
+
expect(filters.map(([label]) => label).sort()).toEqual([
|
|
86
|
+
"concept list --type",
|
|
87
|
+
"implementation list --library",
|
|
88
|
+
"implementation list --platform",
|
|
89
|
+
"standard list --category",
|
|
90
|
+
"token consumers --key",
|
|
91
|
+
"token consumers --state",
|
|
92
|
+
"token consumers --symbol",
|
|
93
|
+
"token consumers --variable",
|
|
94
|
+
"token list --channelOf",
|
|
95
|
+
"token list --type",
|
|
96
|
+
"token values --position",
|
|
97
|
+
"token values --symbol",
|
|
98
|
+
"variable chain --symbol",
|
|
99
|
+
"variable chain --variable",
|
|
100
|
+
"variable list --coordinate",
|
|
101
|
+
"variable list --platform",
|
|
102
|
+
"variable list --symbol",
|
|
103
|
+
"variable list --tier",
|
|
104
|
+
"variable list --visibility",
|
|
105
|
+
]);
|
|
106
|
+
for (const [label, filter] of filters) {
|
|
107
|
+
expect(
|
|
108
|
+
filter.values !== undefined || filter.vocabulary !== undefined,
|
|
109
|
+
`${label} declares neither "values" nor a "vocabulary"`,
|
|
110
|
+
).toBe(true);
|
|
111
|
+
// And never both — a declared set IS the vocabulary.
|
|
112
|
+
expect(
|
|
113
|
+
filter.values !== undefined && filter.vocabulary !== undefined,
|
|
114
|
+
`${label} declares both`,
|
|
115
|
+
).toBe(false);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("every declared story satisfies the compilability rules", () => {
|
|
120
|
+
// These rules are checked in `compileStoryModule`, which is what makes them
|
|
121
|
+
// reach the distribution's own stories rather than only the ones zod sees.
|
|
122
|
+
// Asserted here as a property of the CONFIG so a violation is a red test
|
|
123
|
+
// and not an import-time throw in every command.
|
|
124
|
+
for (const [noun, story] of declaredStories) {
|
|
125
|
+
const issues = storyIssues(story);
|
|
126
|
+
expect(issues, `${noun} has compilability issues`).toEqual([]);
|
|
127
|
+
}
|
|
58
128
|
});
|
|
59
129
|
|
|
60
130
|
it("every declared noun reaches the registry as an overridable module", () => {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Covers the two things `checkNodeVersion` owns beyond the range comparison:
|
|
3
|
+
* the shape of the CheckResult, and that the failure path quotes the declared
|
|
4
|
+
* range rather than a number of its own. The range logic itself is pinned in
|
|
5
|
+
* `isSupportedNodeVersion.test.ts`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
9
|
+
import { SUPPORTED_NODE_RANGE } from "../../../constants.js";
|
|
10
|
+
import { checkNodeVersion } from "./checkNodeVersion.js";
|
|
11
|
+
|
|
12
|
+
/** Swap `process.versions.node`, which is read-only in the normal way. */
|
|
13
|
+
function withNodeVersion(version: string) {
|
|
14
|
+
vi.spyOn(process, "versions", "get").mockReturnValue({
|
|
15
|
+
...process.versions,
|
|
16
|
+
node: version,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
vi.restoreAllMocks();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("checkNodeVersion — reports against the declared range", () => {
|
|
25
|
+
it("passes on a supported version and reports it", async () => {
|
|
26
|
+
withNodeVersion("24.18.1");
|
|
27
|
+
const result = await checkNodeVersion();
|
|
28
|
+
expect(result).toEqual({
|
|
29
|
+
name: "Node version",
|
|
30
|
+
status: "pass",
|
|
31
|
+
detail: "v24.18.1",
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("fails on an unsupported version and quotes the declared range", async () => {
|
|
36
|
+
withNodeVersion("20.19.0");
|
|
37
|
+
const result = await checkNodeVersion();
|
|
38
|
+
expect(result.status).toBe("fail");
|
|
39
|
+
expect(result.detail).toContain("v20.19.0");
|
|
40
|
+
// The range must come from the manifest, never from a literal in the check.
|
|
41
|
+
expect(result.detail).toContain(SUPPORTED_NODE_RANGE);
|
|
42
|
+
expect(result.remedy).toContain(SUPPORTED_NODE_RANGE);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("fails inside the 23.0-23.5 window the range excludes", async () => {
|
|
46
|
+
withNodeVersion("23.2.0");
|
|
47
|
+
expect((await checkNodeVersion()).status).toBe("fail");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -1,25 +1,29 @@
|
|
|
1
|
+
import { SUPPORTED_NODE_RANGE } from "../../../constants.js";
|
|
1
2
|
import type { CheckResult } from "../types.js";
|
|
2
|
-
|
|
3
|
-
const MIN_NODE_MAJOR = 20;
|
|
3
|
+
import { isSupportedNodeVersion } from "./isSupportedNodeVersion.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Check that the Node.js
|
|
6
|
+
* Check that the running Node.js version satisfies this package's declared
|
|
7
|
+
* `engines.node` range.
|
|
8
|
+
*
|
|
9
|
+
* The floor is a property of the manifest, not of this file: a check that
|
|
10
|
+
* hardcodes its own number can disagree with the range the package publishes,
|
|
11
|
+
* and a consumer then passes a check the install contract would have failed.
|
|
7
12
|
*
|
|
8
13
|
* @returns A CheckResult with the current version and pass/fail status.
|
|
9
14
|
* @note Impure — reads `process.versions`.
|
|
10
15
|
*/
|
|
11
16
|
export async function checkNodeVersion(): Promise<CheckResult> {
|
|
12
17
|
const version = process.versions.node;
|
|
13
|
-
const major = Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
14
18
|
|
|
15
|
-
if (
|
|
19
|
+
if (isSupportedNodeVersion(version)) {
|
|
16
20
|
return { name: "Node version", status: "pass", detail: `v${version}` };
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
return {
|
|
20
24
|
name: "Node version",
|
|
21
25
|
status: "fail",
|
|
22
|
-
detail: `v${version} (requires
|
|
23
|
-
remedy: `Install Node.js
|
|
26
|
+
detail: `v${version} (requires ${SUPPORTED_NODE_RANGE})`,
|
|
27
|
+
remedy: `Install Node.js ${SUPPORTED_NODE_RANGE}`,
|
|
24
28
|
};
|
|
25
29
|
}
|