@canonical/pragma-cli 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -0
- package/dist/pragma +0 -0
- package/package.json +19 -15
- package/pragma.conf.ts +664 -0
- package/src/bin.ts +15 -6
- package/src/capabilities/block.parity.test.ts +250 -0
- package/src/capabilities/capabilities/capabilities.render.ts +3 -2
- package/src/capabilities/capabilities/capabilities.test.ts +10 -1
- package/src/capabilities/capabilities/capabilities.verb.ts +32 -14
- package/src/capabilities/capabilities/catalog.ts +20 -8
- package/src/capabilities/capabilities/hints.ts +21 -36
- package/src/capabilities/capabilities/types.ts +2 -0
- package/src/capabilities/colophon/collectColophon.ts +34 -19
- package/src/capabilities/colophon/colophon.render.test.ts +31 -4
- package/src/capabilities/colophon/colophon.render.ts +13 -4
- package/src/capabilities/colophon/colophon.test.ts +3 -3
- package/src/capabilities/colophon/colophon.verb.ts +11 -4
- package/src/capabilities/colophon/markdownTerminal.ts +33 -14
- package/src/capabilities/colophon/types.ts +16 -7
- package/src/capabilities/config/collectConfigShow.test.ts +57 -0
- package/src/capabilities/config/collectConfigShow.ts +41 -4
- package/src/capabilities/config/fields.ts +10 -108
- package/src/capabilities/config/set.test.ts +6 -6
- package/src/capabilities/config/set.verb.ts +12 -8
- package/src/capabilities/config/show.render.test.ts +137 -0
- package/src/capabilities/config/show.render.ts +57 -16
- package/src/capabilities/config/show.verb.ts +9 -8
- package/src/capabilities/config/types.ts +8 -0
- package/src/capabilities/create/byteEquality.subprocess.test.ts +1 -1
- package/src/capabilities/create/byteEquality.test.ts +82 -101
- package/src/capabilities/create/compiledCreate.subprocess.test.ts +53 -16
- package/src/capabilities/create/constants.ts +75 -0
- package/src/capabilities/create/create.mcp.test.ts +2 -2
- package/src/capabilities/create/create.test.ts +192 -16
- package/src/capabilities/create/create.verb.ts +208 -79
- package/src/capabilities/create/index.ts +2 -10
- package/src/capabilities/create/pickGenerator.ts +34 -28
- package/src/capabilities/create/templates.embedded.generated.ts +4 -29
- package/src/capabilities/create/types.ts +10 -6
- package/src/capabilities/{standard/parity.test.ts → distribution.parity.test.ts} +24 -14
- package/src/capabilities/distribution.test.ts +120 -0
- package/src/capabilities/distribution.ts +59 -0
- package/src/capabilities/doctor/checks/checkConfigFile.ts +6 -5
- package/src/capabilities/doctor/checks/checkKeStore.ts +2 -2
- package/src/capabilities/doctor/checks/checkMcpCommands.ts +6 -0
- package/src/capabilities/doctor/checks/checkMcpConfigured.ts +15 -8
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +79 -45
- package/src/capabilities/doctor/checks/checkPragmaVersion.ts +3 -2
- package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +61 -11
- package/src/capabilities/doctor/checks/checkShellCompletions.ts +63 -23
- package/src/capabilities/doctor/checks/checkSkillsSymlinked.ts +3 -2
- package/src/capabilities/doctor/checks/deriveBand.test.ts +42 -0
- package/src/capabilities/doctor/checks/deriveBand.ts +28 -0
- package/src/capabilities/doctor/doctor.render.test.ts +170 -0
- package/src/capabilities/doctor/doctor.render.ts +117 -34
- package/src/capabilities/doctor/doctor.test.ts +68 -9
- package/src/capabilities/doctor/doctor.verb.ts +6 -2
- package/src/capabilities/doctor/runChecks.ts +33 -9
- package/src/capabilities/doctor/types.ts +16 -1
- package/src/capabilities/emptyRecovery.test.ts +32 -15
- package/src/capabilities/graph/inspect.verb.ts +3 -2
- package/src/capabilities/graph/query.verb.ts +3 -2
- package/src/capabilities/graph/runQuery.ts +8 -5
- package/src/capabilities/index.ts +22 -18
- package/src/capabilities/info/collectInfo.ts +10 -6
- package/src/capabilities/info/info.render.ts +3 -2
- package/src/capabilities/info/info.verb.ts +3 -2
- package/src/capabilities/lazy.test.ts +93 -2
- package/src/capabilities/ontology/index.ts +10 -3
- package/src/capabilities/ontology/ontology.test.ts +157 -5
- package/src/capabilities/ontology/verbs.ts +203 -104
- package/src/capabilities/prompt/prompt.render.test.ts +94 -0
- package/src/capabilities/prompt/prompt.render.ts +23 -6
- package/src/capabilities/prompt/prompt.test.ts +68 -1
- package/src/capabilities/prompt/verbs.ts +24 -11
- package/src/capabilities/reference.test.ts +32 -0
- package/src/capabilities/resources/provider.ts +58 -25
- package/src/capabilities/resources/resources.test.ts +176 -21
- package/src/capabilities/scopeTypeSync.test.ts +37 -0
- package/src/capabilities/setup/index.ts +7 -1
- package/src/capabilities/setup/operations/setupCompletions.ts +49 -16
- package/src/capabilities/setup/operations/setupGenerator.ts +166 -63
- package/src/capabilities/setup/operations/setupLsp.ts +56 -12
- package/src/capabilities/setup/operations/setupMcp.ts +216 -39
- package/src/capabilities/setup/operations/setupSkills.ts +10 -4
- package/src/capabilities/setup/setup.render.test.ts +109 -0
- package/src/capabilities/setup/setup.render.ts +61 -14
- package/src/capabilities/setup/setup.test.ts +352 -1
- package/src/capabilities/setup/setup.verb.ts +68 -9
- package/src/capabilities/setup/shell.ts +29 -3
- package/src/capabilities/setup/types.ts +59 -2
- package/src/capabilities/shared/bands.ts +16 -0
- package/src/capabilities/skill/discover.ts +11 -5
- package/src/capabilities/skill/render.ts +4 -5
- package/src/capabilities/skill/verbs.ts +7 -7
- package/src/capabilities/sources/collectStatus.ts +69 -49
- package/src/capabilities/sources/index.ts +1 -1
- package/src/capabilities/sources/installSkills.ts +2 -2
- package/src/capabilities/sources/runUpdate.ts +146 -98
- package/src/capabilities/sources/sources.test.ts +264 -84
- package/src/capabilities/sources/status.render.test.ts +94 -0
- package/src/capabilities/sources/status.render.ts +55 -33
- package/src/capabilities/sources/status.verb.ts +15 -8
- package/src/capabilities/sources/types.ts +18 -25
- package/src/capabilities/sources/update.render.ts +9 -2
- package/src/capabilities/sources/update.verb.ts +12 -23
- package/src/capabilities/surface.test.ts +65 -17
- package/src/capabilities/tier.parity.test.ts +144 -0
- package/src/capabilities/upgrade/upgrade.verb.ts +7 -3
- package/src/constants.test.ts +9 -7
- package/src/constants.ts +49 -23
- package/src/identity.test.ts +333 -0
- package/src/index.ts +2 -2
- package/src/kernel/completion/__snapshots__/emitScripts.test.ts.snap +18 -16
- package/src/kernel/completion/complete.test.ts +3 -5
- package/src/kernel/completion/emitScripts.test.ts +1 -1
- package/src/kernel/completion/emitScripts.ts +4 -2
- package/src/kernel/completion/entitySource.test.ts +185 -41
- package/src/kernel/completion/entitySource.ts +131 -113
- package/src/kernel/completion/model.test.ts +3 -3
- package/src/kernel/completion/model.ts +11 -1
- package/src/kernel/completion/parse.test.ts +2 -4
- package/src/kernel/completion/safety.test.ts +82 -36
- package/src/kernel/completion/shellDrive.test.ts +592 -0
- package/src/kernel/completion/templates/fish.ts +28 -6
- package/src/kernel/completion/types.ts +3 -3
- package/src/kernel/config/__snapshots__/firstRun.test.ts.snap +1 -1
- package/src/kernel/config/defaults.test.ts +85 -0
- package/src/kernel/config/defaults.ts +12 -23
- package/src/kernel/config/evaluateProjectConfig.ts +2 -3
- package/src/kernel/config/findProjectConfig.ts +4 -3
- package/src/kernel/config/firstRun.ts +12 -5
- package/src/kernel/config/globalConfig.ts +2 -2
- package/src/kernel/config/index.ts +4 -5
- package/src/kernel/config/paths.ts +17 -17
- package/src/kernel/config/readConfig.test.ts +242 -6
- package/src/kernel/config/readConfig.ts +8 -8
- package/src/kernel/config/schema.test.ts +50 -0
- package/src/kernel/config/schema.ts +97 -10
- package/src/kernel/config/types.ts +73 -19
- package/src/kernel/copy.test.ts +453 -0
- package/src/kernel/error/PragmaError.test.ts +5 -5
- package/src/kernel/error/constants.ts +3 -2
- package/src/kernel/error/index.ts +1 -1
- package/src/kernel/error/recovery.test.ts +22 -45
- package/src/kernel/error/recovery.ts +22 -27
- package/src/kernel/error/renderError.ts +1 -1
- package/src/kernel/error/types.ts +5 -4
- package/src/kernel/packs/collect.test.ts +195 -11
- package/src/kernel/packs/collect.ts +213 -58
- package/src/kernel/packs/compile.test.ts +163 -7
- package/src/kernel/packs/compile.ts +15 -12
- package/src/kernel/packs/disclosure.test.ts +5 -2
- package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +11 -10
- package/src/kernel/packs/graphqlSource.test.ts +6 -3
- package/src/kernel/packs/iri.ts +5 -7
- package/src/kernel/packs/renderPack.ts +5 -3
- package/src/kernel/packs/resolveEntity.ts +21 -17
- package/src/kernel/packs/runBodies.ts +15 -14
- package/src/kernel/packs/schema.ts +96 -10
- package/src/kernel/packs/sparql/runSelect.test.ts +104 -10
- package/src/kernel/packs/sparql/runSelect.ts +73 -34
- package/src/kernel/packs/toolDescription.test.ts +10 -2
- package/src/kernel/packs/types.ts +39 -4
- package/src/kernel/packs/uniqueness.ts +4 -4
- package/src/kernel/project/cli/buildProgram.test.ts +60 -11
- package/src/kernel/project/cli/buildProgram.ts +11 -0
- package/src/kernel/project/cli/dispatch.test.ts +67 -0
- package/src/kernel/project/cli/dispatch.ts +34 -12
- package/src/kernel/project/cli/globalFlags.test.ts +12 -4
- package/src/kernel/project/cli/globalFlags.ts +14 -14
- package/src/kernel/project/cli/helpFormat.ts +1 -1
- package/src/kernel/project/cli/rootHelp.ts +109 -107
- package/src/kernel/project/mcp/buildServer.ts +11 -6
- package/src/kernel/project/mcp/instructions.ts +12 -7
- package/src/kernel/project/mcp/mcpError.ts +52 -0
- package/src/kernel/project/mcp/parity.test.ts +39 -1
- package/src/kernel/project/mcp/prompts/prompts.test.ts +128 -5
- package/src/kernel/project/mcp/prompts/provider.ts +51 -7
- package/src/kernel/project/mcp/prompts/source.ts +68 -67
- package/src/kernel/project/mcp/registerVerb.ts +25 -6
- package/src/kernel/project/mcp/serve.ts +11 -3
- package/src/kernel/project/mcp/toolDescriptions.test.ts +6 -2
- package/src/kernel/render/disclosure.ts +4 -2
- package/src/kernel/render/formatters.ts +5 -4
- package/src/kernel/render/prefixes.test.ts +36 -0
- package/src/kernel/render/prefixes.ts +40 -13
- package/src/kernel/render/renderers.test.ts +35 -1
- package/src/kernel/render/renderers.ts +25 -7
- package/src/kernel/render/style.test.ts +31 -0
- package/src/kernel/render/style.ts +74 -0
- package/src/kernel/runtime/graphpack/build.ts +57 -3
- package/src/kernel/runtime/graphpack/buildIndex.test.ts +149 -0
- package/src/kernel/runtime/graphpack/buildIndex.ts +173 -50
- package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +5 -8
- package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +3 -4
- package/src/kernel/runtime/graphpack/embedded/pack.stories.generated.ts +3 -0
- package/src/kernel/runtime/graphpack/embedded.ts +37 -11
- package/src/kernel/runtime/graphpack/graphpack.test.ts +274 -6
- package/src/kernel/runtime/graphpack/hash.ts +3 -2
- package/src/kernel/runtime/graphpack/index.ts +1 -1
- package/src/kernel/runtime/graphpack/manifest.ts +114 -12
- package/src/kernel/runtime/graphpack/read.ts +32 -22
- package/src/kernel/runtime/graphpack/schemas.ts +74 -0
- package/src/kernel/runtime/graphpack/stories.ts +84 -0
- package/src/kernel/runtime/graphpack/types.ts +72 -45
- package/src/kernel/runtime/loadSession.ts +4 -12
- package/src/kernel/runtime/paths.ts +64 -15
- package/src/kernel/runtime/probe.test.ts +8 -4
- package/src/kernel/runtime/readEntity.ts +6 -5
- package/src/kernel/runtime/refs/gitOps.ts +1 -19
- package/src/kernel/runtime/refs/parseRef.ts +7 -7
- package/src/kernel/runtime/refs/resolve.ts +141 -65
- package/src/kernel/runtime/resolveSources.test.ts +63 -24
- package/src/kernel/runtime/resolveSources.ts +36 -25
- package/src/kernel/runtime/storeReadiness.ts +62 -0
- package/src/kernel/runtime/storeless.test.ts +1 -1
- package/src/kernel/runtime/types.ts +1 -1
- package/src/kernel/runtime/wasmEmbed.test.ts +25 -20
- package/src/kernel/spec/emitReference.test.ts +196 -0
- package/src/kernel/spec/emitReference.ts +624 -0
- package/src/kernel/spec/emitSurface.ts +13 -7
- package/src/kernel/spec/index.ts +2 -0
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/surfaceConformance.ts +8 -0
- package/src/kernel/spec/types.ts +29 -9
- package/src/kernel/spec/validate.ts +2 -1
- package/src/kernel/vocabulary.test.ts +164 -0
- package/src/kernel/vocabulary.ts +146 -0
- package/src/testing/PARITY_GAPS.ts +9 -3
- package/src/testing/behavioral/README.md +3 -3
- package/src/testing/behavioral/autoLlm.e2e.test.ts +12 -2
- package/src/testing/behavioral/completion.test.ts +21 -8
- package/src/testing/behavioral/disclosure.test.ts +12 -0
- package/src/testing/behavioral/docExamples.test.ts +283 -0
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +4 -3
- package/src/testing/behavioral/errorMatrix.storeless.test.ts +3 -2
- package/src/testing/behavioral/exitCodes.e2e.test.ts +6 -5
- package/src/testing/behavioral/harness.foundation.test.ts +14 -5
- package/src/testing/behavioral/journeys.cli.test.ts +116 -73
- package/src/testing/behavioral/journeys.defaultPack.test.ts +477 -0
- package/src/testing/behavioral/journeys.firstInstall.test.ts +167 -0
- package/src/testing/behavioral/journeys.interactiveTty.e2e.test.ts +66 -0
- package/src/testing/behavioral/journeys.livePack.e2e.test.ts +129 -0
- package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +179 -0
- package/src/testing/behavioral/journeys.packageStories.test.ts +188 -0
- package/src/testing/behavioral/liveReadSurface.ts +4 -3
- package/src/testing/behavioral/mcpSurface.test.ts +10 -5
- package/src/testing/behavioral/staleCommands.test.ts +86 -0
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +9 -9
- package/src/testing/eval/cases/assembly.ts +16 -9
- package/src/testing/eval/cases/effectful.ts +31 -16
- package/src/testing/eval/cases/readNouns.ts +23 -18
- package/src/testing/eval/cases/stable.ts +5 -1
- package/src/testing/eval/eval.test.ts +7 -1
- package/src/testing/fixtures/fixtureCapability.ts +201 -1
- package/src/testing/fixtures/graph/canonical.ts +6 -3
- package/src/testing/fixtures/graph/defaultPack.ts +179 -0
- package/src/testing/fixtures/graph/owlExport.ts +97 -0
- package/src/testing/helpers/extractSnippets.ts +29 -0
- package/src/testing/helpers/fixtureGraph.ts +33 -16
- package/src/testing/helpers/golden.ts +1 -1
- package/src/testing/helpers/packRuntime.ts +2 -3
- package/src/testing/helpers/projectCli.ts +2 -1
- package/src/testing/helpers/projectMcp.ts +6 -0
- package/src/testing/perf/budgets.test.ts +4 -0
- package/src/testing/perf/budgets.ts +22 -7
- package/src/testing/perf/globalSetup.ts +121 -6
- package/src/types.ts +2 -2
- package/src/capabilities/block/blockList.verb.ts +0 -150
- package/src/capabilities/block/index.ts +0 -25
- package/src/capabilities/block/pack.ts +0 -155
- package/src/capabilities/block/parity.test.ts +0 -180
- package/src/capabilities/block/tierChain.ts +0 -78
- package/src/capabilities/colophon/pragmaColophon.ts +0 -66
- package/src/capabilities/config/field.test.ts +0 -188
- package/src/capabilities/modifier/index.ts +0 -15
- package/src/capabilities/modifier/pack.ts +0 -64
- package/src/capabilities/standard/index.ts +0 -18
- package/src/capabilities/standard/pack.ts +0 -128
- package/src/capabilities/tier/index.ts +0 -19
- package/src/capabilities/tier/lookup.render.ts +0 -34
- package/src/capabilities/tier/lookup.test.ts +0 -68
- package/src/capabilities/tier/lookup.verb.ts +0 -44
- package/src/capabilities/tier/pack.ts +0 -28
- package/src/capabilities/tier/runLookup.ts +0 -59
- package/src/capabilities/token/addConfig.render.ts +0 -27
- package/src/capabilities/token/addConfig.test.ts +0 -62
- package/src/capabilities/token/addConfig.verb.ts +0 -40
- package/src/capabilities/token/index.ts +0 -19
- package/src/capabilities/token/pack.ts +0 -58
- package/src/capabilities/token/runAddConfig.ts +0 -95
- package/src/kernel/completion/bashDrive.test.ts +0 -73
- package/src/kernel/runtime/graphpack/embedded/sample.ttl +0 -39
- package/src/kernel/runtime/lock.ts +0 -90
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tier-chain inheritance + channel visibility for the hand-written `block list`.
|
|
3
|
-
*
|
|
4
|
-
* Ported from the v1 filters. Setting a tier activates a parent-chain filter
|
|
5
|
-
* (`apps/lxd` → visible tiers `global`, `apps`, `apps/lxd`); the channel maps to
|
|
6
|
-
* the set of visible release levels. Both are generated SPARQL clauses composed
|
|
7
|
-
* only from validated pack terms — no user input reaches the query text (the
|
|
8
|
-
* tier value comes from config, the channel from a closed enum).
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { Channel } from "../../kernel/config/types.js";
|
|
12
|
-
|
|
13
|
-
/** The `ds:` prefix — the store injects its PREFIX declaration. */
|
|
14
|
-
const DS = "ds:";
|
|
15
|
-
|
|
16
|
-
/** Release levels visible per channel setting. */
|
|
17
|
-
export const CHANNEL_RELEASES: Record<Channel, readonly string[]> = {
|
|
18
|
-
normal: ["stable"],
|
|
19
|
-
experimental: ["stable", "experimental"],
|
|
20
|
-
prerelease: ["stable", "experimental", "alpha", "beta"],
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* The parent chain for a tier path.
|
|
25
|
-
*
|
|
26
|
-
* `apps/lxd` → `["global", "apps", "apps/lxd"]`; `undefined` → `[]` (all tiers).
|
|
27
|
-
*/
|
|
28
|
-
export function resolveTierChain(tierPath: string | undefined): string[] {
|
|
29
|
-
if (tierPath === undefined) return [];
|
|
30
|
-
const normalized = tierPath.trim().toLowerCase();
|
|
31
|
-
const chain: string[] = ["global"];
|
|
32
|
-
const segments = normalized.split("/");
|
|
33
|
-
for (let i = 0; i < segments.length; i++) {
|
|
34
|
-
const path = segments.slice(0, i + 1).join("/");
|
|
35
|
-
if (path !== "global") chain.push(path);
|
|
36
|
-
}
|
|
37
|
-
return chain;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** A tier path's URI local name (slashes → underscores: `apps/lxd` → `apps_lxd`). */
|
|
41
|
-
export function tierPathToLocal(tierPath: string): string {
|
|
42
|
-
return tierPath.trim().toLowerCase().replace(/\//g, "_");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* A SPARQL FILTER clause for tier visibility, or empty when no tier is set.
|
|
47
|
-
*
|
|
48
|
-
* @param tierPath - The configured tier path (e.g. `apps/lxd`) or `undefined`.
|
|
49
|
-
* @param varName - The SPARQL variable to filter (default `tier`).
|
|
50
|
-
*/
|
|
51
|
-
export function buildTierFilter(
|
|
52
|
-
tierPath: string | undefined,
|
|
53
|
-
varName = "tier",
|
|
54
|
-
): string {
|
|
55
|
-
if (tierPath === undefined) return "";
|
|
56
|
-
const uriList = resolveTierChain(tierPath)
|
|
57
|
-
.map((t) => `${DS}${tierPathToLocal(t)}`)
|
|
58
|
-
.join(", ");
|
|
59
|
-
return `FILTER(?${varName} IN (${uriList}))`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* SPARQL clauses for channel visibility: bind `?release` if present, then filter
|
|
64
|
-
* to allowed levels OR unbound (unannotated blocks are treated as stable).
|
|
65
|
-
*
|
|
66
|
-
* @param channel - The configured channel.
|
|
67
|
-
* @param varName - The SPARQL variable to bind/filter (default `release`).
|
|
68
|
-
*/
|
|
69
|
-
export function buildChannelFilter(
|
|
70
|
-
channel: Channel,
|
|
71
|
-
varName = "release",
|
|
72
|
-
): string {
|
|
73
|
-
const uriList = CHANNEL_RELEASES[channel].map((r) => `${DS}${r}`).join(", ");
|
|
74
|
-
return [
|
|
75
|
-
`OPTIONAL { ?component ${DS}release ?${varName} }`,
|
|
76
|
-
`FILTER(!BOUND(?${varName}) || ?${varName} IN (${uriList}))`,
|
|
77
|
-
].join("\n ");
|
|
78
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The built-in pragma colophon — how the toolchain itself is made. Authored
|
|
3
|
-
* Markdown grounded in this tree's real architecture; surfaced by `pragma
|
|
4
|
-
* colophon` as the first section, before any active pack's domain colophon.
|
|
5
|
-
*
|
|
6
|
-
* `PRAGMA_COLOPHON` is the full narrative for humans; `PRAGMA_COLOPHON_SUMMARY`
|
|
7
|
-
* is the condensed form `--llm` emits (Markdown IS the agent-optimal shape).
|
|
8
|
-
* Both are BODIES with no leading H1 — the renderer supplies the "pragma"
|
|
9
|
-
* heading, so the section is never double-titled.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/** The full built-in colophon (Markdown body). */
|
|
13
|
-
export const PRAGMA_COLOPHON = `pragma is a **domain-based toolchain**: one CLI and one MCP server projected
|
|
14
|
-
from a single grammar, serving a knowledge-graph domain that reads as data.
|
|
15
|
-
|
|
16
|
-
## The effect monad
|
|
17
|
-
|
|
18
|
-
Reads are plain \`async\` functions; a mutation instead *describes* its effects
|
|
19
|
-
as a \`Task\` (\`@canonical/task\`) that is interpreted — under the real node
|
|
20
|
-
interpreter, a \`--dry-run\` planner, or an \`--undo\` reverser. Describe-then-
|
|
21
|
-
interpret means dry-run and undo come for free, and the dispatcher tells the two
|
|
22
|
-
worlds apart on one bit: \`capability.mutates\`.
|
|
23
|
-
|
|
24
|
-
## One grammar, many projections
|
|
25
|
-
|
|
26
|
-
Every capability is a \`VerbSpec\` — a noun, its params, its effect profile, its
|
|
27
|
-
formatters. The CLI commands, the MCP tools, shell completion, and the
|
|
28
|
-
surface/docs are all *projections* of that one shape, so they cannot drift. The
|
|
29
|
-
projected surface is frozen in a covenant (\`surface/surface.v2.json\`): a single
|
|
30
|
-
source of truth a test asserts the live grammar still emits, tool for tool.
|
|
31
|
-
|
|
32
|
-
## LLM-optimized output
|
|
33
|
-
|
|
34
|
-
Each verb renders three ways — \`plain\` for a terminal, \`json\` for the machine
|
|
35
|
-
envelope, and \`llm\` for condensed Markdown. \`--llm\` (or a non-interactive
|
|
36
|
-
stdout) selects the agent form: the same data, shaped for a model to read. This
|
|
37
|
-
colophon is itself a showcase of that render model.
|
|
38
|
-
|
|
39
|
-
## Modular, storeless by construction
|
|
40
|
-
|
|
41
|
-
Capabilities ship as **modules** — named bundles of verbs with optional
|
|
42
|
-
boot / resource / prompt hooks. A verb declares whether it \`needsStore\`, and
|
|
43
|
-
the dispatcher boots the triple store *only* for those; a storeless verb
|
|
44
|
-
(\`info\`, \`config\`, \`capabilities\`, \`colophon\`) never pays for the graph.
|
|
45
|
-
|
|
46
|
-
## Scaffolding
|
|
47
|
-
|
|
48
|
-
\`pragma create\` scaffolds components, packages, and applications through the
|
|
49
|
-
\`@canonical/summon-*\` generators, reusing summon's rich Ink wizard when it runs
|
|
50
|
-
interactively.
|
|
51
|
-
|
|
52
|
-
## The domain reads as data
|
|
53
|
-
|
|
54
|
-
A domain is a **pack**: a declarative \`PackDefinition\` (its list / lookup
|
|
55
|
-
queries) compiled into verbs, backed by a content-addressed graphpack that
|
|
56
|
-
\`sources update\` builds once. Swap the pack and the same pragma serves a
|
|
57
|
-
different domain — including the domain colophon printed below this one.`;
|
|
58
|
-
|
|
59
|
-
/** The condensed colophon for `--llm` (Markdown body, no leading H1). */
|
|
60
|
-
export const PRAGMA_COLOPHON_SUMMARY = `pragma is a domain-based toolchain: one CLI + MCP server projected from a single \`VerbSpec\` grammar.
|
|
61
|
-
|
|
62
|
-
- **Effect monad** (\`@canonical/task\`): reads are async; a mutation returns an interpreted \`Task\`, so \`--dry-run\` and \`--undo\` are free. The dispatcher branches on \`capability.mutates\`.
|
|
63
|
-
- **One grammar, many projections**: CLI, MCP tools, completion, and docs all project one \`VerbSpec\`; the emitted surface is frozen in a covenant so the projections never drift.
|
|
64
|
-
- **LLM-optimized output**: every verb renders \`plain\` / \`json\` / \`llm\`; \`--llm\` emits condensed Markdown for agents.
|
|
65
|
-
- **Modular + storeless**: capability modules; the triple store boots only for \`needsStore\` verbs.
|
|
66
|
-
- **Domain as data**: a pack is a declarative \`PackDefinition\` compiled to verbs over a content-addressed graph built by \`sources update\`.`;
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `config tier` / `channel` / `detail` — storeless, covenant-exact setters.
|
|
3
|
-
*
|
|
4
|
-
* Pins the emitted shape against the golden slice, exercises set / reset-sentinel
|
|
5
|
-
* / enum-reject / `--dry-run` plan / MCP plan-first-vs-confirm, and holds the
|
|
6
|
-
* storeless invariant (a config write never boots the store).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
10
|
-
import { tmpdir } from "node:os";
|
|
11
|
-
import { join } from "node:path";
|
|
12
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
13
|
-
import { globalConfigPath } from "../../kernel/config/paths.js";
|
|
14
|
-
import { CHANNELS } from "../../kernel/config/types.js";
|
|
15
|
-
import { PragmaError } from "../../kernel/error/PragmaError.js";
|
|
16
|
-
import {
|
|
17
|
-
executeVerb,
|
|
18
|
-
extractParams,
|
|
19
|
-
} from "../../kernel/project/cli/dispatch.js";
|
|
20
|
-
import { bootRuntime } from "../../kernel/runtime/boot.js";
|
|
21
|
-
import type { GlobalFlags, PragmaRuntime } from "../../kernel/runtime/types.js";
|
|
22
|
-
import { emitVerb } from "../../kernel/spec/emitSurface.js";
|
|
23
|
-
import type { VerbSpec } from "../../kernel/spec/types.js";
|
|
24
|
-
import { projectMcp } from "../../testing/helpers/projectMcp.js";
|
|
25
|
-
import { CONFIG_FIELDS } from "./fields.js";
|
|
26
|
-
import { configModule } from "./index.js";
|
|
27
|
-
import { runField } from "./runField.js";
|
|
28
|
-
|
|
29
|
-
const FLAGS: GlobalFlags = {
|
|
30
|
-
llm: false,
|
|
31
|
-
autoLlm: false,
|
|
32
|
-
format: "plain",
|
|
33
|
-
verbose: false,
|
|
34
|
-
};
|
|
35
|
-
const REAL = { dryRun: false, undo: false, yes: false };
|
|
36
|
-
const DRY = { dryRun: true, undo: false, yes: false };
|
|
37
|
-
|
|
38
|
-
const verbOf = (field: string): VerbSpec =>
|
|
39
|
-
configModule.verbs.find((v) => v.path[1] === field) as VerbSpec;
|
|
40
|
-
const tierVerb = verbOf("tier");
|
|
41
|
-
const channelVerb = verbOf("channel");
|
|
42
|
-
const detailVerb = verbOf("detail");
|
|
43
|
-
|
|
44
|
-
let prevXdg: string | undefined;
|
|
45
|
-
const roots: string[] = [];
|
|
46
|
-
const tmp = (prefix: string): string => {
|
|
47
|
-
const dir = mkdtempSync(join(tmpdir(), prefix));
|
|
48
|
-
roots.push(dir);
|
|
49
|
-
return dir;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
beforeEach(() => {
|
|
53
|
-
prevXdg = process.env.XDG_CONFIG_HOME;
|
|
54
|
-
process.env.XDG_CONFIG_HOME = tmp("pragma-cfgfield-xdg-");
|
|
55
|
-
});
|
|
56
|
-
afterEach(() => {
|
|
57
|
-
process.env.XDG_CONFIG_HOME = prevXdg;
|
|
58
|
-
for (const dir of roots) rmSync(dir, { recursive: true, force: true });
|
|
59
|
-
roots.length = 0;
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
function readGlobal(): Record<string, unknown> {
|
|
63
|
-
return JSON.parse(readFileSync(globalConfigPath(), "utf-8"));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
describe("config setters — covenant-exact emission (PROTECTED)", () => {
|
|
67
|
-
it("emits the golden slice for each field", () => {
|
|
68
|
-
expect(emitVerb(tierVerb)).toEqual({
|
|
69
|
-
v: "tier",
|
|
70
|
-
args: ["<path>"],
|
|
71
|
-
mutates: true,
|
|
72
|
-
mcp: "config_tier",
|
|
73
|
-
});
|
|
74
|
-
expect(emitVerb(channelVerb)).toEqual({
|
|
75
|
-
v: "channel",
|
|
76
|
-
args: ["<name>"],
|
|
77
|
-
mutates: true,
|
|
78
|
-
mcp: "config_channel",
|
|
79
|
-
});
|
|
80
|
-
expect(emitVerb(detailVerb)).toEqual({
|
|
81
|
-
v: "detail",
|
|
82
|
-
args: ["<level>"],
|
|
83
|
-
mutates: true,
|
|
84
|
-
mcp: "config_detail",
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe("config setters — write & reset", () => {
|
|
90
|
-
it("set writes the field to the GLOBAL config and never boots the store", async () => {
|
|
91
|
-
const rt: PragmaRuntime = bootRuntime(FLAGS, tmp("pragma-proj-"));
|
|
92
|
-
const outcome = await executeVerb(tierVerb, { path: "apps/lxd" }, REAL, rt);
|
|
93
|
-
|
|
94
|
-
expect(outcome.exitCode).toBe(0);
|
|
95
|
-
expect(outcome.stdout).toContain("Set tier = apps/lxd");
|
|
96
|
-
expect(readGlobal().tier).toBe("apps/lxd");
|
|
97
|
-
// Storeless invariant: a config write never touches the store factory.
|
|
98
|
-
expect(rt.store.booted).toBe(false);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it("channel/detail write their enum value", async () => {
|
|
102
|
-
const rt = bootRuntime(FLAGS, tmp("pragma-proj-"));
|
|
103
|
-
await executeVerb(channelVerb, { name: "experimental" }, REAL, rt);
|
|
104
|
-
await executeVerb(detailVerb, { level: "detailed" }, REAL, rt);
|
|
105
|
-
const written = readGlobal();
|
|
106
|
-
expect(written.channel).toBe("experimental");
|
|
107
|
-
expect(written.detail).toBe("detailed");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("a reset sentinel removes the tier field", async () => {
|
|
111
|
-
const cwd = tmp("pragma-proj-");
|
|
112
|
-
await executeVerb(
|
|
113
|
-
tierVerb,
|
|
114
|
-
{ path: "apps/lxd" },
|
|
115
|
-
REAL,
|
|
116
|
-
bootRuntime(FLAGS, cwd),
|
|
117
|
-
);
|
|
118
|
-
expect(readGlobal().tier).toBe("apps/lxd");
|
|
119
|
-
|
|
120
|
-
const outcome = await executeVerb(
|
|
121
|
-
tierVerb,
|
|
122
|
-
{ path: "none" },
|
|
123
|
-
REAL,
|
|
124
|
-
bootRuntime(FLAGS, cwd),
|
|
125
|
-
);
|
|
126
|
-
expect(outcome.stdout).toContain("Reset tier");
|
|
127
|
-
expect("tier" in readGlobal()).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("config setters — enum rejection", () => {
|
|
132
|
-
it("the CLI coerce layer rejects a non-member with INVALID_INPUT + validOptions", () => {
|
|
133
|
-
let caught: unknown;
|
|
134
|
-
try {
|
|
135
|
-
extractParams(channelVerb.params, ["bogus"], {});
|
|
136
|
-
} catch (error) {
|
|
137
|
-
caught = error;
|
|
138
|
-
}
|
|
139
|
-
expect(caught).toBeInstanceOf(PragmaError);
|
|
140
|
-
expect((caught as PragmaError).code).toBe("INVALID_INPUT");
|
|
141
|
-
expect((caught as PragmaError).validOptions).toEqual([...CHANNELS]);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it("runField backstops a bad enum value before it reaches disk", () => {
|
|
145
|
-
const channelSpec = CONFIG_FIELDS.find((s) => s.field === "channel");
|
|
146
|
-
expect(() =>
|
|
147
|
-
runField(channelSpec as (typeof CONFIG_FIELDS)[number], {
|
|
148
|
-
name: "bogus",
|
|
149
|
-
}),
|
|
150
|
-
).toThrow(/Invalid channel/);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe("config setters — dry-run plan", () => {
|
|
155
|
-
it("--dry-run shows the WriteFile plan and writes nothing", async () => {
|
|
156
|
-
const rt = bootRuntime(FLAGS, tmp("pragma-proj-"));
|
|
157
|
-
const outcome = await executeVerb(tierVerb, { path: "apps/lxd" }, DRY, rt);
|
|
158
|
-
|
|
159
|
-
expect(outcome.exitCode).toBe(0);
|
|
160
|
-
expect(outcome.stdout).toContain("Write file");
|
|
161
|
-
expect(outcome.stdout).toContain(globalConfigPath());
|
|
162
|
-
expect(existsSync(globalConfigPath())).toBe(false);
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
describe("config setters — MCP plan-first / confirm parity", () => {
|
|
167
|
-
it("config_tier returns a plan without confirm, writes with confirm:true", async () => {
|
|
168
|
-
const cwd = tmp("pragma-proj-");
|
|
169
|
-
const mcp = await projectMcp([configModule], cwd);
|
|
170
|
-
|
|
171
|
-
const plan = await mcp.callTool("config_tier", { path: "apps/lxd" });
|
|
172
|
-
expect(plan.ok).toBe(true);
|
|
173
|
-
expect(plan.meta).toMatchObject({ planOnly: true, confirmRequired: true });
|
|
174
|
-
const planLines = (plan.data as { plan: string[] }).plan;
|
|
175
|
-
expect(planLines.some((line) => line.includes("Write file"))).toBe(true);
|
|
176
|
-
expect(existsSync(globalConfigPath())).toBe(false);
|
|
177
|
-
|
|
178
|
-
const done = await mcp.callTool("config_tier", {
|
|
179
|
-
path: "apps/lxd",
|
|
180
|
-
confirm: true,
|
|
181
|
-
});
|
|
182
|
-
await mcp.cleanup();
|
|
183
|
-
|
|
184
|
-
expect(done.ok).toBe(true);
|
|
185
|
-
expect(done.data).toMatchObject({ field: "tier", value: "apps/lxd" });
|
|
186
|
-
expect(readGlobal().tier).toBe("apps/lxd");
|
|
187
|
-
});
|
|
188
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `modifier` capability module — the bundled pack (SPARQL list, GraphQL
|
|
3
|
-
* lookup) compiled to verbs.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { compilePack } from "../../kernel/packs/compile.js";
|
|
7
|
-
import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
|
|
8
|
-
import type { CapabilityModule } from "../../kernel/spec/types.js";
|
|
9
|
-
import { modifierPack } from "./pack.js";
|
|
10
|
-
|
|
11
|
-
/** The `modifier` capability module (`list`, `lookup`). */
|
|
12
|
-
export const modifierModule: CapabilityModule = {
|
|
13
|
-
name: "modifier",
|
|
14
|
-
verbs: compilePack(modifierPack, "bundled:modifier", DEFAULT_PREFIX_MAP),
|
|
15
|
-
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The bundled `modifier` pack — modifier families as data.
|
|
3
|
-
*
|
|
4
|
-
* `modifier list` is SPARQL (an alternation path collects values asserted in
|
|
5
|
-
* either direction); `modifier lookup` is GRAPHQL, where the compiled
|
|
6
|
-
* `ModifierFamily.modifiers` field is the declared-inverse union and resolves
|
|
7
|
-
* both directions in ONE generated document — exactly the case the GraphQL fetch
|
|
8
|
-
* path exists for.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { PackDefinition } from "../../kernel/packs/types.js";
|
|
12
|
-
|
|
13
|
-
export const modifierPack: PackDefinition = {
|
|
14
|
-
noun: "modifier",
|
|
15
|
-
description: "List all modifier families.",
|
|
16
|
-
toolDescription:
|
|
17
|
-
"List all modifier families with their values. Use when browsing which modifier families exist and the values each allows. Example: modifier_list {}.",
|
|
18
|
-
list: {
|
|
19
|
-
query: [
|
|
20
|
-
"SELECT ?uri ?name",
|
|
21
|
-
' (GROUP_CONCAT(DISTINCT ?valueName; separator=", ") AS ?values)',
|
|
22
|
-
"WHERE {",
|
|
23
|
-
" ?uri a ds:ModifierFamily ;",
|
|
24
|
-
" ds:name ?name .",
|
|
25
|
-
" OPTIONAL {",
|
|
26
|
-
" ?uri (ds:hasModifier|^ds:modifierFamily) ?value .",
|
|
27
|
-
" ?value ds:name ?valueName .",
|
|
28
|
-
" }",
|
|
29
|
-
"}",
|
|
30
|
-
"GROUP BY ?uri ?name",
|
|
31
|
-
"ORDER BY ?name",
|
|
32
|
-
].join("\n"),
|
|
33
|
-
columns: [
|
|
34
|
-
{ field: "uri", label: "IRI" },
|
|
35
|
-
{ field: "name", label: "Name" },
|
|
36
|
-
{ field: "values", label: "Values" },
|
|
37
|
-
],
|
|
38
|
-
emptyRecovery: {
|
|
39
|
-
message:
|
|
40
|
-
"No modifier families in the store. Build it from the configured design-system packages.",
|
|
41
|
-
cli: "pragma sources update",
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
lookup: {
|
|
45
|
-
source: "graphql",
|
|
46
|
-
by: "ds:name",
|
|
47
|
-
type: "ds:ModifierFamily",
|
|
48
|
-
toolDescription:
|
|
49
|
-
'Get values and usage details for one or more modifier families by name. Use when you need the allowed values of specific families. Example: modifier_lookup { names: ["importance"] }.',
|
|
50
|
-
expand: [
|
|
51
|
-
{
|
|
52
|
-
name: "values",
|
|
53
|
-
heading: "Values",
|
|
54
|
-
relation: "ds:hasModifier",
|
|
55
|
-
select: [{ name: "name", property: "ds:name" }],
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
sample: {
|
|
59
|
-
fixedCount: true,
|
|
60
|
-
toolDescription:
|
|
61
|
-
"Return randomly selected complete modifier families (with value lists) as exemplars. Use BEFORE writing queries to see actual data shapes.",
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `standard` capability module — the bundled pack compiled to verbs.
|
|
3
|
-
*
|
|
4
|
-
* Compiled at import (fast-path safe: compilePack is pure/zod-free) so the module
|
|
5
|
-
* is surface-deterministic. A config/package story for `standard` overrides it at
|
|
6
|
-
* dispatch (see kernel/packs/collect).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { compilePack } from "../../kernel/packs/compile.js";
|
|
10
|
-
import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
|
|
11
|
-
import type { CapabilityModule } from "../../kernel/spec/types.js";
|
|
12
|
-
import { standardPack } from "./pack.js";
|
|
13
|
-
|
|
14
|
-
/** The `standard` capability module (list, categories, lookup, sample). */
|
|
15
|
-
export const standardModule: CapabilityModule = {
|
|
16
|
-
name: "standard",
|
|
17
|
-
verbs: compilePack(standardPack, "bundled:standard", DEFAULT_PREFIX_MAP),
|
|
18
|
-
};
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The bundled `standard` pack — code standards as data.
|
|
3
|
-
*
|
|
4
|
-
* `standard list|lookup|categories|sample` compile from this definition through
|
|
5
|
-
* the one pack kernel. Normalized for v2: the old `digest` level is renamed to
|
|
6
|
-
* the canonical `standard`, so disclosure gates by the canonical index; the
|
|
7
|
-
* default is `summary` (base fields by name), `--detail standard` adds the `dos`
|
|
8
|
-
* examples, `--detail detailed` adds `donts`. `cs:extends` stays the raw IRI in
|
|
9
|
-
* JSON (renderers compact it at display time).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { PackDefinition } from "../../kernel/packs/types.js";
|
|
13
|
-
|
|
14
|
-
export const standardPack: PackDefinition = {
|
|
15
|
-
noun: "standard",
|
|
16
|
-
description: "List all code standards.",
|
|
17
|
-
toolDescription:
|
|
18
|
-
"List code standards. Optionally filter by category or search term.",
|
|
19
|
-
list: {
|
|
20
|
-
query: [
|
|
21
|
-
"SELECT ?uri ?name ?category ?description",
|
|
22
|
-
"WHERE {",
|
|
23
|
-
" ?uri a cs:CodeStandard ;",
|
|
24
|
-
" cs:description ?description .",
|
|
25
|
-
" OPTIONAL { ?uri cs:name ?n . }",
|
|
26
|
-
' BIND(COALESCE(?n, REPLACE(STRAFTER(STR(?uri), "#"), "\\\\.", "/")) AS ?name)',
|
|
27
|
-
" OPTIONAL {",
|
|
28
|
-
" ?uri cs:hasCategory ?cat .",
|
|
29
|
-
" ?cat cs:slug ?category .",
|
|
30
|
-
" }",
|
|
31
|
-
"}",
|
|
32
|
-
"ORDER BY ?name",
|
|
33
|
-
].join("\n"),
|
|
34
|
-
columns: [
|
|
35
|
-
{ field: "uri", label: "IRI" },
|
|
36
|
-
{ field: "name", label: "Name" },
|
|
37
|
-
{ field: "category", label: "Category" },
|
|
38
|
-
{ field: "description", label: "Description" },
|
|
39
|
-
],
|
|
40
|
-
filters: [
|
|
41
|
-
{
|
|
42
|
-
param: "category",
|
|
43
|
-
variable: "category",
|
|
44
|
-
description: "Filter by category name.",
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
search: {
|
|
48
|
-
variables: ["name", "description"],
|
|
49
|
-
description: "Search in name and description.",
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
verbs: [
|
|
53
|
-
{
|
|
54
|
-
verb: "categories",
|
|
55
|
-
description: "List all standard categories with counts.",
|
|
56
|
-
toolDescription: "List all code standard categories.",
|
|
57
|
-
query: [
|
|
58
|
-
"SELECT ?name (COUNT(?standard) AS ?count)",
|
|
59
|
-
"WHERE {",
|
|
60
|
-
" ?cat a cs:Category ;",
|
|
61
|
-
" cs:slug ?name .",
|
|
62
|
-
" OPTIONAL {",
|
|
63
|
-
" ?standard a cs:CodeStandard ;",
|
|
64
|
-
" cs:hasCategory ?cat .",
|
|
65
|
-
" }",
|
|
66
|
-
"}",
|
|
67
|
-
"GROUP BY ?name",
|
|
68
|
-
"ORDER BY ?name",
|
|
69
|
-
].join("\n"),
|
|
70
|
-
columns: [
|
|
71
|
-
{ field: "name", label: "Category" },
|
|
72
|
-
{ field: "count", label: "Standards" },
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
lookup: {
|
|
77
|
-
source: "sparql",
|
|
78
|
-
by: "cs:name",
|
|
79
|
-
type: "cs:CodeStandard",
|
|
80
|
-
description:
|
|
81
|
-
"Look up detailed information for a standard by name, IRI, or glob.",
|
|
82
|
-
toolDescription:
|
|
83
|
-
"Get detailed information about one or more code standards including dos and donts with code examples. Address standards by name, prefixed name (cs:…), absolute IRI, or glob pattern (react/component/*).",
|
|
84
|
-
fields: [
|
|
85
|
-
{
|
|
86
|
-
name: "category",
|
|
87
|
-
property: "cs:hasCategory/cs:slug",
|
|
88
|
-
label: "Category",
|
|
89
|
-
},
|
|
90
|
-
{ name: "description", property: "cs:description", label: "Description" },
|
|
91
|
-
{ name: "extends", property: "cs:extends", label: "Extends" },
|
|
92
|
-
],
|
|
93
|
-
expand: [
|
|
94
|
-
{
|
|
95
|
-
name: "dos",
|
|
96
|
-
heading: "Do",
|
|
97
|
-
relation: "cs:do",
|
|
98
|
-
select: [
|
|
99
|
-
{ name: "caption", property: "cs:description" },
|
|
100
|
-
{ name: "language", property: "cs:language" },
|
|
101
|
-
{ name: "code", property: "cs:code" },
|
|
102
|
-
],
|
|
103
|
-
level: "standard",
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
name: "donts",
|
|
107
|
-
heading: "Don't",
|
|
108
|
-
relation: "cs:dont",
|
|
109
|
-
select: [
|
|
110
|
-
{ name: "caption", property: "cs:description" },
|
|
111
|
-
{ name: "language", property: "cs:language" },
|
|
112
|
-
{ name: "code", property: "cs:code" },
|
|
113
|
-
],
|
|
114
|
-
level: "detailed",
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
disclosure: {
|
|
118
|
-
levels: ["summary", "standard", "detailed"],
|
|
119
|
-
default: "summary",
|
|
120
|
-
},
|
|
121
|
-
sample: {
|
|
122
|
-
description:
|
|
123
|
-
"Return randomly selected complete standard instances as exemplars for shape discovery.",
|
|
124
|
-
toolDescription:
|
|
125
|
-
"Return 1–5 randomly selected complete code standard instances as exemplars. Use BEFORE writing queries to see actual data shapes, property names, and value formats. Each call returns different instances.",
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `tier` capability module — the bundled flat-list pack compiled to `list`.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { compilePack } from "../../kernel/packs/compile.js";
|
|
6
|
-
import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
|
|
7
|
-
import type { CapabilityModule } from "../../kernel/spec/types.js";
|
|
8
|
-
import { tierLookupVerb } from "./lookup.verb.js";
|
|
9
|
-
import { tierPack } from "./pack.js";
|
|
10
|
-
|
|
11
|
-
/** The `tier` capability module — the bundled flat-list pack plus the bespoke
|
|
12
|
-
* single-name `lookup` (a pack lookup would emit the variadic `<name...>`). */
|
|
13
|
-
export const tierModule: CapabilityModule = {
|
|
14
|
-
name: "tier",
|
|
15
|
-
verbs: [
|
|
16
|
-
...compilePack(tierPack, "bundled:tier", DEFAULT_PREFIX_MAP),
|
|
17
|
-
tierLookupVerb,
|
|
18
|
-
],
|
|
19
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Formatters + data shape for `tier lookup <name>`.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Formatters } from "../../kernel/spec/types.js";
|
|
6
|
-
|
|
7
|
-
/** The looked-up tier: its IRI, name, and the blocks scoped directly to it. */
|
|
8
|
-
export interface TierLookupData {
|
|
9
|
-
readonly uri: string;
|
|
10
|
-
readonly name: string;
|
|
11
|
-
readonly blocks: readonly string[];
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const tierLookupFormatters: Formatters<TierLookupData> = {
|
|
15
|
-
plain(data) {
|
|
16
|
-
const lines = [`${data.name} (${data.uri})`];
|
|
17
|
-
lines.push(
|
|
18
|
-
data.blocks.length > 0
|
|
19
|
-
? ` blocks: ${data.blocks.join(", ")}`
|
|
20
|
-
: " blocks: (none scoped directly to this tier)",
|
|
21
|
-
);
|
|
22
|
-
return lines.join("\n");
|
|
23
|
-
},
|
|
24
|
-
llm(data) {
|
|
25
|
-
const lines = [`# ${data.name}`, `- IRI: \`${data.uri}\``];
|
|
26
|
-
if (data.blocks.length > 0) {
|
|
27
|
-
lines.push(`- Blocks: ${data.blocks.map((b) => `\`${b}\``).join(", ")}`);
|
|
28
|
-
}
|
|
29
|
-
return lines.join("\n");
|
|
30
|
-
},
|
|
31
|
-
json(data) {
|
|
32
|
-
return JSON.stringify(data);
|
|
33
|
-
},
|
|
34
|
-
};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
2
|
-
import type { PragmaRuntime } from "../../kernel/runtime/types.js";
|
|
3
|
-
import { CANONICAL_TTL } from "../../testing/fixtures/graph/canonical.js";
|
|
4
|
-
import {
|
|
5
|
-
bootFixtureRuntime,
|
|
6
|
-
type FixtureGraph,
|
|
7
|
-
} from "../../testing/helpers/fixtureGraph.js";
|
|
8
|
-
import type { McpHarness } from "../../testing/helpers/projectMcp.js";
|
|
9
|
-
import { projectMcp } from "../../testing/helpers/projectMcp.js";
|
|
10
|
-
import { capabilities } from "../index.js";
|
|
11
|
-
import { runTierLookup } from "./runLookup.js";
|
|
12
|
-
|
|
13
|
-
let fixture: FixtureGraph;
|
|
14
|
-
let mcp: McpHarness;
|
|
15
|
-
|
|
16
|
-
beforeAll(async () => {
|
|
17
|
-
fixture = await bootFixtureRuntime({ ttl: CANONICAL_TTL });
|
|
18
|
-
mcp = await projectMcp(capabilities, fixture.cwd);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterAll(async () => {
|
|
22
|
-
await mcp.cleanup();
|
|
23
|
-
await fixture.dispose();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
describe("tier_lookup — bespoke single-name lookup (PROTECTED)", () => {
|
|
27
|
-
it("resolves a tier and the blocks scoped directly to it", async () => {
|
|
28
|
-
const result = await mcp.callTool("tier_lookup", { name: "apps/lxd" });
|
|
29
|
-
expect(result.ok).toBe(true);
|
|
30
|
-
const data = result.data as { name: string; blocks: string[] };
|
|
31
|
-
expect(data.name).toBe("apps/lxd");
|
|
32
|
-
// The canonical fixture scopes "LXD Panel" to apps/lxd.
|
|
33
|
-
expect(data.blocks).toContain("LXD Panel");
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("errors on an unknown tier name with a tier_list recovery", async () => {
|
|
37
|
-
const result = await mcp.callTool("tier_lookup", { name: "not-a-tier" });
|
|
38
|
-
expect(result.ok).toBe(false);
|
|
39
|
-
const error = result.error as { code: string };
|
|
40
|
-
expect(error.code).toBe("ENTITY_NOT_FOUND");
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe("tier_lookup — cold/unseeded store (ROOT A)", () => {
|
|
45
|
-
it("remaps a 'Prefix not found' to STORE_UNAVAILABLE, not INTERNAL_ERROR", async () => {
|
|
46
|
-
// The bespoke lookup used to call `rt.query.sparql` directly, bypassing the
|
|
47
|
-
// `runSelect` remap — so a cold store's raw "Prefix not found" collapsed to
|
|
48
|
-
// INTERNAL_ERROR. It now routes through `runSelect`, inheriting the remap.
|
|
49
|
-
const coldRuntime = {
|
|
50
|
-
query: {
|
|
51
|
-
sparql: async () => {
|
|
52
|
-
throw new Error("Prefix not found: ds");
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
} as unknown as PragmaRuntime;
|
|
56
|
-
|
|
57
|
-
let caught: unknown;
|
|
58
|
-
try {
|
|
59
|
-
await runTierLookup(coldRuntime, "apps/lxd");
|
|
60
|
-
} catch (error) {
|
|
61
|
-
caught = error;
|
|
62
|
-
}
|
|
63
|
-
expect(caught).toMatchObject({ code: "STORE_UNAVAILABLE" });
|
|
64
|
-
expect(
|
|
65
|
-
(caught as { recovery?: { mcp?: { tool: string } } }).recovery?.mcp,
|
|
66
|
-
).toMatchObject({ tool: "sources_update" });
|
|
67
|
-
});
|
|
68
|
-
});
|