@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,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The token-graph nouns through the REAL CLI projector (PROTECTED).
|
|
3
|
+
*
|
|
4
|
+
* The parity suites call `verb.run()` directly, which proves the queries and
|
|
5
|
+
* says nothing about the command line a person actually types. Two of this
|
|
6
|
+
* surface's design decisions live entirely in that layer and are invisible to a
|
|
7
|
+
* `run()` call:
|
|
8
|
+
*
|
|
9
|
+
* - a declared filter reaches the command line as `--<kebab-case>`, so a
|
|
10
|
+
* camelCase param is the only spelling that produces a readable two-word
|
|
11
|
+
* flag. `channelOf` has to arrive as `--channel-of` and come back as
|
|
12
|
+
* `channelOf` in the param bag, and both halves are asserted here because a
|
|
13
|
+
* mismatch would be a flag the help text advertises and the run body never
|
|
14
|
+
* receives.
|
|
15
|
+
* - a `--`-prefixed positional CANNOT be typed. That is the whole reason a
|
|
16
|
+
* variable is published without its leading dashes, and it is a claim about
|
|
17
|
+
* the parser, not about the story — so it is reproduced against the parser
|
|
18
|
+
* rather than asserted in a comment.
|
|
19
|
+
*
|
|
20
|
+
* Parsed, never run: a `preAction` hook captures the resolved command and
|
|
21
|
+
* throws before the action, so no runtime boots and no store is needed.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { Command } from "commander";
|
|
25
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
26
|
+
import { verbKey } from "../kernel/packs/uniqueness.js";
|
|
27
|
+
import { dispatch } from "../kernel/project/cli/dispatch.js";
|
|
28
|
+
import type { GlobalFlags } from "../kernel/runtime/types.js";
|
|
29
|
+
import type { VerbSpec } from "../kernel/spec/types.js";
|
|
30
|
+
import { projectCli } from "../testing/helpers/projectCli.js";
|
|
31
|
+
import { storyModules } from "./distribution.js";
|
|
32
|
+
|
|
33
|
+
const modules = ["token", "variable"].map((noun) => {
|
|
34
|
+
const module = storyModules.get(noun);
|
|
35
|
+
if (!module) throw new Error(`pragma.conf.ts declares no "${noun}" story`);
|
|
36
|
+
return module;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/** What a parse resolved to, thrown out of the hook before the action runs. */
|
|
40
|
+
class Parsed extends Error {
|
|
41
|
+
constructor(
|
|
42
|
+
readonly path: string,
|
|
43
|
+
readonly args: string[],
|
|
44
|
+
readonly opts: Record<string, unknown>,
|
|
45
|
+
) {
|
|
46
|
+
super(path);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Parse an argv through the real program, without running the verb. */
|
|
51
|
+
async function parse(argv: string[]): Promise<Parsed> {
|
|
52
|
+
const program = projectCli(modules);
|
|
53
|
+
program.exitOverride();
|
|
54
|
+
program.configureOutput({ writeErr: () => {}, writeOut: () => {} });
|
|
55
|
+
for (const noun of program.commands) {
|
|
56
|
+
noun.exitOverride();
|
|
57
|
+
noun.configureOutput({ writeErr: () => {}, writeOut: () => {} });
|
|
58
|
+
for (const verb of noun.commands) {
|
|
59
|
+
verb.exitOverride();
|
|
60
|
+
verb.configureOutput({ writeErr: () => {}, writeOut: () => {} });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
program.hook("preAction", (_root, action) => {
|
|
64
|
+
const parent = action.parent?.name();
|
|
65
|
+
const path =
|
|
66
|
+
parent !== undefined && parent !== "pragma"
|
|
67
|
+
? `${parent} ${action.name()}`
|
|
68
|
+
: action.name();
|
|
69
|
+
throw new Parsed(path, [...action.args], action.opts());
|
|
70
|
+
});
|
|
71
|
+
try {
|
|
72
|
+
await program.parseAsync(argv, { from: "user" });
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof Parsed) return error;
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`argv did not route to a verb: ${argv.join(" ")}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The registered long flags of one `<noun> <verb>` command. */
|
|
81
|
+
function flagsOf(noun: string, verb: string): string[] {
|
|
82
|
+
const program = projectCli(modules);
|
|
83
|
+
const command = program.commands
|
|
84
|
+
.find((c) => c.name() === noun)
|
|
85
|
+
?.commands.find((c) => c.name() === verb) as Command | undefined;
|
|
86
|
+
if (!command) throw new Error(`no CLI command "${noun} ${verb}"`);
|
|
87
|
+
return command.options
|
|
88
|
+
.map((option) => option.long)
|
|
89
|
+
.filter((long): long is string => long !== undefined);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
describe("the projected command line (PROTECTED)", () => {
|
|
93
|
+
it("projects every declared verb as a command", () => {
|
|
94
|
+
const program = projectCli(modules);
|
|
95
|
+
const commands = program.commands.flatMap((noun) =>
|
|
96
|
+
noun.commands.map((verb) => `${noun.name()} ${verb.name()}`),
|
|
97
|
+
);
|
|
98
|
+
expect(commands.sort()).toEqual([
|
|
99
|
+
"token consumers",
|
|
100
|
+
"token list",
|
|
101
|
+
"token lookup",
|
|
102
|
+
"token sample",
|
|
103
|
+
"token values",
|
|
104
|
+
"variable chain",
|
|
105
|
+
"variable list",
|
|
106
|
+
"variable lookup",
|
|
107
|
+
"variable sample",
|
|
108
|
+
]);
|
|
109
|
+
// And the compiled modules agree, so the projector is not inventing or
|
|
110
|
+
// dropping one.
|
|
111
|
+
expect(
|
|
112
|
+
modules.flatMap((m) => m.verbs.map((v) => verbKey(v.path))).sort(),
|
|
113
|
+
).toEqual(commands.sort());
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("registers a camelCase filter param in KEBAB form", () => {
|
|
117
|
+
// The one two-word dimension in this surface. `--channelof` would have been
|
|
118
|
+
// the only spelling the old grammar admitted, and it reads as a typo.
|
|
119
|
+
expect(flagsOf("token", "list")).toEqual([
|
|
120
|
+
"--type",
|
|
121
|
+
"--channel-of",
|
|
122
|
+
"--search",
|
|
123
|
+
"--limit",
|
|
124
|
+
"--after",
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("hands the run body back the DECLARED param name", async () => {
|
|
129
|
+
// The other half: the flag is kebab, the param bag key is the declared
|
|
130
|
+
// camelCase name the story filters on. A mismatch here would be a flag the
|
|
131
|
+
// help advertises and the run body never sees.
|
|
132
|
+
//
|
|
133
|
+
// COLLECTED into an array, because a declared filter is repeatable and a
|
|
134
|
+
// repeated filter is a union over its values. One occurrence is therefore a
|
|
135
|
+
// one-element array rather than a bare string, and the run body reads it
|
|
136
|
+
// the same way either way.
|
|
137
|
+
const result = await parse(["token", "list", "--channel-of", "color.text"]);
|
|
138
|
+
expect(result.path).toBe("token list");
|
|
139
|
+
expect(result.opts).toMatchObject({ channelOf: ["color.text"] });
|
|
140
|
+
const twice = await parse([
|
|
141
|
+
"token",
|
|
142
|
+
"list",
|
|
143
|
+
"--channel-of",
|
|
144
|
+
"color.text",
|
|
145
|
+
"--channel-of",
|
|
146
|
+
"color.border",
|
|
147
|
+
]);
|
|
148
|
+
expect(twice.opts).toMatchObject({
|
|
149
|
+
channelOf: ["color.text", "color.border"],
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("carries the page pair on every list-shaped verb", () => {
|
|
154
|
+
for (const [noun, verb] of [
|
|
155
|
+
["token", "list"],
|
|
156
|
+
["token", "values"],
|
|
157
|
+
["token", "consumers"],
|
|
158
|
+
["variable", "list"],
|
|
159
|
+
["variable", "chain"],
|
|
160
|
+
] as const) {
|
|
161
|
+
expect(flagsOf(noun, verb), `${noun} ${verb}`).toEqual(
|
|
162
|
+
expect.arrayContaining(["--limit", "--after"]),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("gives the two lookups a variadic positional and no page pair", () => {
|
|
168
|
+
for (const noun of ["token", "variable"]) {
|
|
169
|
+
const flags = flagsOf(noun, "lookup");
|
|
170
|
+
expect(flags).not.toContain("--limit");
|
|
171
|
+
const parsed = parse([noun, "lookup", "a", "b"]);
|
|
172
|
+
return parsed.then((result) => {
|
|
173
|
+
expect(result.args).toEqual(["a", "b"]);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("the names these nouns publish are typable (PROTECTED)", () => {
|
|
180
|
+
it("accepts a DOTTED symbol name as a positional", async () => {
|
|
181
|
+
const parsed = await parse(["token", "lookup", "color.text"]);
|
|
182
|
+
expect(parsed.path).toBe("token lookup");
|
|
183
|
+
expect(parsed.args).toEqual(["color.text"]);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("accepts a dash-stripped variable name as a positional", async () => {
|
|
187
|
+
const parsed = await parse(["variable", "lookup", "color-text"]);
|
|
188
|
+
expect(parsed.path).toBe("variable lookup");
|
|
189
|
+
expect(parsed.args).toEqual(["color-text"]);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("REFUSES the raw CSS name, which is why the dashes are stripped", async () => {
|
|
193
|
+
// Reproduced against the parser rather than asserted in prose: a
|
|
194
|
+
// `--`-prefixed positional is read as an option, so a noun publishing
|
|
195
|
+
// `--color-text` would name something no caller could pass. This is the
|
|
196
|
+
// measurement the published name is derived from.
|
|
197
|
+
await expect(
|
|
198
|
+
parse(["variable", "lookup", "--color-text"]),
|
|
199
|
+
).rejects.toMatchObject({
|
|
200
|
+
message: expect.stringContaining("unknown option"),
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("accepts a dotted position and a dotted style key as flag values", async () => {
|
|
205
|
+
// Both are values rather than positionals, so a dot in them is ordinary —
|
|
206
|
+
// but they are the spellings the stories publish, so they are exercised.
|
|
207
|
+
const values = await parse([
|
|
208
|
+
"token",
|
|
209
|
+
"values",
|
|
210
|
+
"--position",
|
|
211
|
+
"mode.dark",
|
|
212
|
+
"--symbol",
|
|
213
|
+
"color.text",
|
|
214
|
+
]);
|
|
215
|
+
expect(values.opts).toMatchObject({
|
|
216
|
+
position: ["mode.dark"],
|
|
217
|
+
symbol: ["color.text"],
|
|
218
|
+
});
|
|
219
|
+
const consumers = await parse([
|
|
220
|
+
"token",
|
|
221
|
+
"consumers",
|
|
222
|
+
"--key",
|
|
223
|
+
"appearance.background",
|
|
224
|
+
"--variable",
|
|
225
|
+
"color-text",
|
|
226
|
+
]);
|
|
227
|
+
expect(consumers.opts).toMatchObject({
|
|
228
|
+
key: ["appearance.background"],
|
|
229
|
+
variable: ["color-text"],
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe("a stray positional is refused, not ignored (PROTECTED)", () => {
|
|
235
|
+
const PLAIN: GlobalFlags = {
|
|
236
|
+
llm: false,
|
|
237
|
+
autoLlm: false,
|
|
238
|
+
format: "plain",
|
|
239
|
+
verbose: false,
|
|
240
|
+
};
|
|
241
|
+
const savedExit = process.exitCode;
|
|
242
|
+
afterEach(() => {
|
|
243
|
+
process.exitCode = savedExit;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const chain = (storyModules.get("variable")?.verbs ?? []).find(
|
|
247
|
+
(verb) => verbKey(verb.path) === "variable chain",
|
|
248
|
+
) as VerbSpec;
|
|
249
|
+
|
|
250
|
+
it("the parser hands the stray word to the action — nothing stops it there", async () => {
|
|
251
|
+
// Half the defect: a sub-verb-only noun opts into excess operands to keep
|
|
252
|
+
// its "unknown command" suggestion, and Commander copies that opt-in down
|
|
253
|
+
// to every verb attached under it. So `variable chain color-text` parses.
|
|
254
|
+
const parsed = await parse(["variable", "chain", "color-text"]);
|
|
255
|
+
expect(parsed.path).toBe("variable chain");
|
|
256
|
+
expect(parsed.args).toEqual(["color-text"]);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("`variable chain color-text` refuses, naming the flag it belonged to", async () => {
|
|
260
|
+
// The other half: the verb declares no positional, so the word used to be
|
|
261
|
+
// dropped on the floor and the unfiltered chain printed 300 rows about
|
|
262
|
+
// something else entirely.
|
|
263
|
+
expect(chain.params.some((param) => param.positional)).toBe(false);
|
|
264
|
+
const errs: string[] = [];
|
|
265
|
+
const spy = vi
|
|
266
|
+
.spyOn(process.stderr, "write")
|
|
267
|
+
.mockImplementation((chunk: string | Uint8Array) => {
|
|
268
|
+
errs.push(String(chunk));
|
|
269
|
+
return true;
|
|
270
|
+
});
|
|
271
|
+
await dispatch(chain, ["color-text"], {}, PLAIN);
|
|
272
|
+
spy.mockRestore();
|
|
273
|
+
|
|
274
|
+
const out = errs.join("");
|
|
275
|
+
expect(out).toContain("takes no positional argument");
|
|
276
|
+
expect(out).toContain("Did you mean `--variable color-text`?");
|
|
277
|
+
expect(process.exitCode).toBe(2);
|
|
278
|
+
});
|
|
279
|
+
});
|