@canonical/pragma-cli 0.27.0 → 0.29.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/dist/pragma +0 -0
- package/package.json +19 -17
- package/src/config/readConfig.ts +38 -2
- package/src/config/types.ts +12 -1
- package/src/config/writeConfig.ts +12 -0
- package/src/constants.ts +12 -1
- package/src/domains/block/commands/index.ts +2 -1
- package/src/domains/block/commands/sample.ts +55 -0
- package/src/domains/block/formatters/index.ts +2 -1
- package/src/domains/block/formatters/sample.ts +21 -0
- package/src/domains/block/index.ts +3 -3
- package/src/domains/block/mcp/specs.ts +48 -0
- package/src/domains/block/operations/index.ts +2 -1
- package/src/domains/block/operations/lookup.ts +9 -0
- package/src/domains/block/operations/sample.ts +41 -0
- package/src/domains/block/orchestration/blockEmptyError.test.ts +26 -0
- package/src/domains/block/orchestration/resolveBlockLookup.ts +10 -3
- package/src/domains/config/commands/framework.test.ts +88 -0
- package/src/domains/config/commands/framework.ts +85 -0
- package/src/domains/config/commands/index.ts +2 -0
- package/src/domains/config/commands/trace.test.ts +148 -0
- package/src/domains/config/commands/trace.ts +80 -0
- package/src/domains/config/formatters/framework.ts +34 -0
- package/src/domains/config/formatters/index.ts +2 -0
- package/src/domains/config/formatters/trace.ts +28 -0
- package/src/domains/config/index.ts +15 -2
- package/src/domains/config/operations/index.ts +1 -0
- package/src/domains/config/operations/validateFramework.ts +24 -0
- package/src/domains/config/tasks/index.ts +2 -0
- package/src/domains/config/tasks/setChannel.ts +7 -1
- package/src/domains/config/tasks/setFramework.ts +40 -0
- package/src/domains/config/tasks/setTier.ts +7 -1
- package/src/domains/config/tasks/setTrace.ts +38 -0
- package/src/domains/doctor/operations/checks/checkKeStore.ts +5 -5
- package/src/domains/doctor/operations/checks/checkPackageRefs.ts +35 -41
- package/src/domains/doctor/operations/checks.test.ts +4 -1
- package/src/domains/doctor/operations/runChecks.test.ts +72 -0
- package/src/domains/doctor/operations/runChecks.ts +48 -12
- package/src/domains/graphql/commands/build.test.ts +194 -0
- package/src/domains/graphql/commands/build.ts +125 -0
- package/src/domains/graphql/commands/check.test.ts +139 -0
- package/src/domains/graphql/commands/check.ts +87 -0
- package/src/domains/graphql/commands/index.ts +4 -0
- package/src/domains/graphql/formatters/index.ts +3 -0
- package/src/domains/graphql/formatters/report.ts +78 -0
- package/src/domains/graphql/helpers/index.ts +4 -0
- package/src/domains/graphql/helpers/parsePrefixes.test.ts +44 -0
- package/src/domains/graphql/helpers/parsePrefixes.ts +38 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +56 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.ts +45 -0
- package/src/domains/graphql/index.ts +21 -0
- package/src/domains/graphql/operations/compileSchema.test.ts +119 -0
- package/src/domains/graphql/operations/compileSchema.ts +109 -0
- package/src/domains/graphql/operations/index.ts +7 -0
- package/src/domains/graphql/types.ts +29 -0
- package/src/domains/info/operations/collectInfo.test.ts +2 -2
- package/src/domains/info/operations/collectInfo.ts +4 -4
- package/src/domains/llm/capabilities.test.ts +91 -0
- package/src/domains/llm/commands/capabilities.ts +28 -0
- package/src/domains/llm/commands/index.ts +1 -0
- package/src/domains/llm/data/commandReference.ts +90 -18
- package/src/domains/llm/data/decisionTrees.ts +15 -13
- package/src/domains/llm/data/index.ts +2 -0
- package/src/domains/llm/data/toolCatalog.ts +184 -0
- package/src/domains/llm/formatters/capabilities.ts +50 -0
- package/src/domains/llm/formatters/index.ts +1 -0
- package/src/domains/llm/index.ts +3 -2
- package/src/domains/llm/mcp/index.ts +1 -1
- package/src/domains/llm/mcp/specs.ts +59 -52
- package/src/domains/llm/types.ts +40 -0
- package/src/domains/modifier/commands/index.ts +2 -1
- package/src/domains/modifier/commands/sample.ts +53 -0
- package/src/domains/modifier/formatters/index.ts +2 -1
- package/src/domains/modifier/formatters/sample.ts +15 -0
- package/src/domains/modifier/index.ts +7 -3
- package/src/domains/modifier/mcp/specs.ts +47 -0
- package/src/domains/modifier/operations/index.ts +2 -1
- package/src/domains/modifier/operations/lookup.ts +9 -0
- package/src/domains/modifier/operations/sample.ts +32 -0
- package/src/domains/modifier/orchestration/modifierEmptyError.test.ts +26 -0
- package/src/domains/modifier/orchestration/modifierEmptyError.ts +7 -2
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +14 -2
- package/src/domains/refs/operations/index.ts +1 -1
- package/src/domains/refs/operations/paths.ts +29 -1
- package/src/domains/refs/operations/updateRefs.test.ts +6 -3
- package/src/domains/refs/operations/updateRefs.ts +3 -2
- package/src/domains/shared/bootStore.ts +88 -49
- package/src/domains/shared/contracts.ts +1 -0
- package/src/domains/shared/emptyErrorRecovery.test.ts +109 -0
- package/src/domains/shared/loaders/bundledLoader.ts +108 -0
- package/src/domains/shared/loaders/gitLoader.ts +31 -0
- package/src/domains/shared/loaders/index.ts +6 -0
- package/src/domains/shared/loaders/localLoader.ts +73 -0
- package/src/domains/shared/loaders/readPackageDir.ts +112 -0
- package/src/domains/shared/lookupMany.ts +9 -1
- package/src/domains/shared/packages.ts +21 -120
- package/src/domains/shared/pickRandom.ts +22 -0
- package/src/domains/shared/runtime.ts +6 -3
- package/src/domains/shared/sampleFormatters.ts +47 -0
- package/src/domains/shared/semanticPackage.ts +96 -0
- package/src/domains/shared/suggestions/detectCrossDomain.test.ts +43 -0
- package/src/domains/shared/suggestions/detectCrossDomain.ts +116 -0
- package/src/domains/shared/suggestions/expandGlob.test.ts +92 -0
- package/src/domains/shared/suggestions/expandGlob.ts +51 -0
- package/src/domains/shared/suggestions/expandLookupQueries.ts +57 -0
- package/src/domains/shared/suggestions/index.ts +7 -0
- package/src/domains/shared/suggestions/listDomainNames.ts +61 -0
- package/src/domains/shared/suggestions/suggestNames.test.ts +70 -0
- package/src/domains/shared/suggestions/suggestNames.ts +97 -0
- package/src/domains/shared/types/index.ts +1 -0
- package/src/domains/shared/types/runtime.ts +4 -1
- package/src/domains/shared/types/sample.ts +17 -0
- package/src/domains/skill/helpers/resolveSkillSources.ts +49 -16
- package/src/domains/standard/commands/index.ts +2 -1
- package/src/domains/standard/commands/sample.ts +57 -0
- package/src/domains/standard/formatters/index.ts +2 -1
- package/src/domains/standard/formatters/sample.ts +15 -0
- package/src/domains/standard/index.ts +8 -1
- package/src/domains/standard/mcp/specs.ts +48 -1
- package/src/domains/standard/operations/index.ts +2 -1
- package/src/domains/standard/operations/lookup.ts +9 -0
- package/src/domains/standard/operations/sample.ts +35 -0
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +14 -2
- package/src/domains/standard/orchestration/standardEmptyError.test.ts +33 -0
- package/src/domains/standard/orchestration/standardEmptyError.ts +16 -6
- package/src/domains/token/commands/index.ts +2 -1
- package/src/domains/token/commands/sample.ts +53 -0
- package/src/domains/token/formatters/index.ts +2 -1
- package/src/domains/token/formatters/sample.ts +16 -0
- package/src/domains/token/index.ts +8 -1
- package/src/domains/token/mcp/specs.ts +47 -1
- package/src/domains/token/operations/index.ts +2 -1
- package/src/domains/token/operations/lookup.ts +9 -0
- package/src/domains/token/operations/sample.ts +32 -0
- package/src/domains/token/orchestration/resolveTokenLookup.ts +14 -2
- package/src/domains/token/orchestration/tokenEmptyError.test.ts +33 -0
- package/src/domains/token/orchestration/tokenEmptyError.ts +5 -2
- package/src/domains/trace/commands/clear.ts +71 -0
- package/src/domains/trace/commands/index.ts +5 -0
- package/src/domains/trace/commands/sessions.ts +32 -0
- package/src/domains/trace/commands/show.ts +145 -0
- package/src/domains/trace/formatters/index.ts +9 -0
- package/src/domains/trace/formatters/sessions.ts +80 -0
- package/src/domains/trace/formatters/show.ts +122 -0
- package/src/domains/trace/index.ts +17 -0
- package/src/domains/trace/operations/index.ts +8 -0
- package/src/domains/trace/operations/listSessions.test.ts +55 -0
- package/src/domains/trace/operations/listSessions.ts +52 -0
- package/src/domains/trace/operations/readTraceLog.test.ts +100 -0
- package/src/domains/trace/operations/readTraceLog.ts +104 -0
- package/src/domains/trace/tracePlugin.test.ts +171 -0
- package/src/domains/trace/tracePlugin.ts +159 -0
- package/src/domains/trace/types.ts +65 -0
- package/src/error/PragmaError.ts +15 -2
- package/src/error/types.ts +15 -1
- package/src/mcp/error/serializeErrorPayload.ts +7 -0
- package/src/mcp/error/types.ts +8 -0
- package/src/mcp/registerResources.test.ts +38 -16
- package/src/mcp/registerResources.ts +57 -8
- package/src/mcp/tools/registerTools.test.ts +22 -7
- package/src/mcp/utils/wrapTool.test.ts +1 -0
- package/src/pipeline/collectCommands.ts +7 -1
- package/src/pipeline/renderError.ts +15 -0
- package/src/pipeline/resolveCommandKind.ts +8 -1
- package/src/pipeline/runCli.ts +12 -1
- package/src/testing/createTestMcpClient.ts +1 -0
- package/src/testing/graphqlFixtures.ts +72 -0
- package/src/testing/index.ts +7 -0
- package/src/testing/integration/mcp-surface.test.ts +11 -5
|
@@ -135,6 +135,53 @@ async function listAllSubjects(store: Store): Promise<string[]> {
|
|
|
135
135
|
return result.bindings.map((b) => b.s ?? "").filter((s) => isUri(s));
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
const RDFS_LABEL = "http://www.w3.org/2000/01/rdf-schema#label";
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Fetch the rdfs:label of the entity's rdf:type class.
|
|
142
|
+
*
|
|
143
|
+
* Returns the label of the first typed class that has one, or null.
|
|
144
|
+
*/
|
|
145
|
+
async function fetchTypeLabel(
|
|
146
|
+
store: Store,
|
|
147
|
+
fullUri: string,
|
|
148
|
+
): Promise<string | null> {
|
|
149
|
+
const result = await store.query(
|
|
150
|
+
buildQuery(`
|
|
151
|
+
SELECT ?typeLabel
|
|
152
|
+
WHERE {
|
|
153
|
+
<${fullUri}> <${RDF_TYPE}> ?type .
|
|
154
|
+
?type <${RDFS_LABEL}> ?typeLabel .
|
|
155
|
+
}
|
|
156
|
+
LIMIT 1
|
|
157
|
+
`),
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
if (result.type !== "select" || result.bindings.length === 0) return null;
|
|
161
|
+
return result.bindings[0]?.typeLabel ?? null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Build a resource description from type label and graph description.
|
|
166
|
+
*
|
|
167
|
+
* Produces: "Component — Buttons are used to trigger…" or just "Component"
|
|
168
|
+
* when no description exists, or just the truncated description when no
|
|
169
|
+
* type is recognized.
|
|
170
|
+
*/
|
|
171
|
+
function buildResourceDescription(
|
|
172
|
+
typeLabel: string | null,
|
|
173
|
+
description: string | null,
|
|
174
|
+
): string | undefined {
|
|
175
|
+
if (!typeLabel && !description) return undefined;
|
|
176
|
+
const truncated =
|
|
177
|
+
description && description.length > 120
|
|
178
|
+
? `${description.slice(0, 117)}...`
|
|
179
|
+
: description;
|
|
180
|
+
if (!typeLabel) return truncated ?? undefined;
|
|
181
|
+
if (!truncated) return typeLabel;
|
|
182
|
+
return `${typeLabel} — ${truncated}`;
|
|
183
|
+
}
|
|
184
|
+
|
|
138
185
|
/**
|
|
139
186
|
* Read a single entity: all its triples with level-1 object summaries.
|
|
140
187
|
*/
|
|
@@ -234,17 +281,23 @@ export default function registerResources(
|
|
|
234
281
|
const { store } = runtime;
|
|
235
282
|
const prefixes = store.prefixes;
|
|
236
283
|
|
|
237
|
-
const template = new ResourceTemplate("
|
|
284
|
+
const template = new ResourceTemplate("{+uri}", {
|
|
238
285
|
list: async () => {
|
|
239
286
|
const subjects = await listAllSubjects(store);
|
|
240
287
|
const resources = await Promise.all(
|
|
241
288
|
subjects.map(async (fullUri) => {
|
|
242
289
|
const prefixed = compactUri(fullUri, prefixes);
|
|
243
|
-
const label = await
|
|
290
|
+
const [label, typeLabel, desc] = await Promise.all([
|
|
291
|
+
fetchLabel(store, fullUri, prefixes),
|
|
292
|
+
fetchTypeLabel(store, fullUri),
|
|
293
|
+
fetchDescription(store, fullUri, prefixes),
|
|
294
|
+
]);
|
|
244
295
|
return {
|
|
245
|
-
uri:
|
|
296
|
+
uri: prefixed,
|
|
246
297
|
name: label ?? prefixed,
|
|
298
|
+
description: buildResourceDescription(typeLabel, desc),
|
|
247
299
|
mimeType: "application/json" as const,
|
|
300
|
+
annotations: { audience: ["assistant" as const] },
|
|
248
301
|
};
|
|
249
302
|
}),
|
|
250
303
|
);
|
|
@@ -264,11 +317,7 @@ export default function registerResources(
|
|
|
264
317
|
server.registerResource(
|
|
265
318
|
"graph-entity",
|
|
266
319
|
template,
|
|
267
|
-
{
|
|
268
|
-
description:
|
|
269
|
-
"An entity in the pragma knowledge graph. Returns all properties with level-1 relation summaries.",
|
|
270
|
-
mimeType: "application/json",
|
|
271
|
-
},
|
|
320
|
+
{ mimeType: "application/json" },
|
|
272
321
|
async (url, variables) => {
|
|
273
322
|
try {
|
|
274
323
|
const prefixedUri = variables.uri as string;
|
|
@@ -52,9 +52,9 @@ function parseData(result: Record<string, unknown>): unknown {
|
|
|
52
52
|
// =============================================================================
|
|
53
53
|
|
|
54
54
|
describe("tool listing", () => {
|
|
55
|
-
it("registers
|
|
55
|
+
it("registers 29 tools", async () => {
|
|
56
56
|
const { tools } = await client.listTools();
|
|
57
|
-
expect(tools).toHaveLength(
|
|
57
|
+
expect(tools).toHaveLength(29);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
it("all tools have descriptions", async () => {
|
|
@@ -94,6 +94,11 @@ describe("tool listing", () => {
|
|
|
94
94
|
expect(names).toContain("doctor");
|
|
95
95
|
expect(names).toContain("info");
|
|
96
96
|
expect(names).toContain("capabilities");
|
|
97
|
+
// Sample tools
|
|
98
|
+
expect(names).toContain("block_sample");
|
|
99
|
+
expect(names).toContain("standard_sample");
|
|
100
|
+
expect(names).toContain("token_sample");
|
|
101
|
+
expect(names).toContain("modifier_sample");
|
|
97
102
|
});
|
|
98
103
|
|
|
99
104
|
it("no tool names contain pragma_ prefix", async () => {
|
|
@@ -1020,13 +1025,16 @@ describe("info", () => {
|
|
|
1020
1025
|
// =============================================================================
|
|
1021
1026
|
|
|
1022
1027
|
describe("capabilities", () => {
|
|
1023
|
-
it("returns
|
|
1028
|
+
it("returns enriched tool catalog with counts", async () => {
|
|
1024
1029
|
const result = await client.callTool({
|
|
1025
1030
|
name: "capabilities",
|
|
1026
1031
|
arguments: {},
|
|
1027
1032
|
});
|
|
1028
1033
|
const data = parseData(result) as {
|
|
1029
|
-
|
|
1034
|
+
version: string;
|
|
1035
|
+
conventions: Record<string, string>;
|
|
1036
|
+
discovery_sequence: { stage: number; tool: string; purpose: string }[];
|
|
1037
|
+
tools: { name: string; category: string; use_when: string }[];
|
|
1030
1038
|
counts: {
|
|
1031
1039
|
total: number;
|
|
1032
1040
|
read: number;
|
|
@@ -1034,14 +1042,21 @@ describe("capabilities", () => {
|
|
|
1034
1042
|
orientation: number;
|
|
1035
1043
|
diagnostic: number;
|
|
1036
1044
|
};
|
|
1045
|
+
limits: Record<string, unknown>;
|
|
1037
1046
|
};
|
|
1038
|
-
|
|
1039
|
-
expect(
|
|
1040
|
-
expect(
|
|
1047
|
+
const toolNames = data.tools.map((t) => t.name);
|
|
1048
|
+
expect(toolNames).toContain("block_list");
|
|
1049
|
+
expect(toolNames).toContain("capabilities");
|
|
1050
|
+
expect(data.tools.every((t) => t.use_when.length > 0)).toBe(true);
|
|
1051
|
+
expect(data.counts.total).toBe(29);
|
|
1041
1052
|
expect(data.counts.read).toBeGreaterThan(0);
|
|
1042
1053
|
expect(data.counts.write).toBe(5);
|
|
1043
1054
|
expect(data.counts.orientation).toBe(2);
|
|
1044
1055
|
expect(data.counts.diagnostic).toBe(2);
|
|
1056
|
+
expect(data.version).toBeDefined();
|
|
1057
|
+
expect(data.conventions).toBeDefined();
|
|
1058
|
+
expect(data.discovery_sequence.length).toBe(3);
|
|
1059
|
+
expect(data.limits).toBeDefined();
|
|
1045
1060
|
});
|
|
1046
1061
|
});
|
|
1047
1062
|
|
|
@@ -4,8 +4,12 @@ import { commands as configCommands } from "../domains/config/index.js";
|
|
|
4
4
|
import { commands as createCommands } from "../domains/create/index.js";
|
|
5
5
|
import { doctorCommand } from "../domains/doctor/commands/index.js";
|
|
6
6
|
import { commands as graphCommands } from "../domains/graph/index.js";
|
|
7
|
+
import { commands as graphqlCommands } from "../domains/graphql/index.js";
|
|
7
8
|
import { infoCommand, upgradeCommand } from "../domains/info/index.js";
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
buildCapabilitiesCommand,
|
|
11
|
+
buildLlmCommand,
|
|
12
|
+
} from "../domains/llm/index.js";
|
|
9
13
|
import { commands as modifierCommands } from "../domains/modifier/index.js";
|
|
10
14
|
import { commands as ontologyCommands } from "../domains/ontology/index.js";
|
|
11
15
|
import { commands as setupCommands } from "../domains/setup/index.js";
|
|
@@ -38,10 +42,12 @@ export default function collectCommands(
|
|
|
38
42
|
...blockCommands(ctx),
|
|
39
43
|
...ontologyCommands(ctx),
|
|
40
44
|
...graphCommands(ctx),
|
|
45
|
+
...graphqlCommands(),
|
|
41
46
|
...skillCommands(ctx),
|
|
42
47
|
doctorCommand,
|
|
43
48
|
infoCommand,
|
|
44
49
|
upgradeCommand,
|
|
45
50
|
buildLlmCommand(ctx),
|
|
51
|
+
buildCapabilitiesCommand(),
|
|
46
52
|
];
|
|
47
53
|
}
|
|
@@ -43,6 +43,14 @@ function renderErrorPlain(error: PragmaError): string {
|
|
|
43
43
|
lines.push(`Valid options: ${error.validOptions.join(", ")}`);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
if (error.crossDomain) {
|
|
47
|
+
lines.push("");
|
|
48
|
+
lines.push(
|
|
49
|
+
`"${error.entity?.name ?? ""}" exists as a ${error.crossDomain.entityType}.`,
|
|
50
|
+
);
|
|
51
|
+
lines.push(`Run \`${error.crossDomain.cli}\``);
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
if (error.recovery) {
|
|
47
55
|
lines.push("");
|
|
48
56
|
if (error.recovery.cli) {
|
|
@@ -82,6 +90,12 @@ function renderErrorLlm(error: PragmaError): string {
|
|
|
82
90
|
lines.push(`Valid options: ${error.validOptions.join(", ")}`);
|
|
83
91
|
}
|
|
84
92
|
|
|
93
|
+
if (error.crossDomain) {
|
|
94
|
+
lines.push(
|
|
95
|
+
`Cross-domain: "${error.entity?.name ?? ""}" exists as a ${error.crossDomain.entityType}. \`${error.crossDomain.cli}\``,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
85
99
|
if (error.recovery) {
|
|
86
100
|
if (error.recovery.cli) {
|
|
87
101
|
lines.push(`Recovery: \`${error.recovery.cli}\``);
|
|
@@ -106,6 +120,7 @@ function renderErrorJson(error: PragmaError): string {
|
|
|
106
120
|
entity: error.entity,
|
|
107
121
|
suggestions: error.suggestions,
|
|
108
122
|
recovery: error.recovery,
|
|
123
|
+
crossDomain: error.crossDomain,
|
|
109
124
|
filters: error.filters,
|
|
110
125
|
validOptions: error.validOptions,
|
|
111
126
|
});
|
|
@@ -8,7 +8,14 @@
|
|
|
8
8
|
import type { CommandKind } from "./types.js";
|
|
9
9
|
|
|
10
10
|
/** Commands that do not require the ke store to be booted. */
|
|
11
|
-
const STORE_SKIP_COMMANDS = new Set([
|
|
11
|
+
const STORE_SKIP_COMMANDS = new Set([
|
|
12
|
+
"setup",
|
|
13
|
+
"mcp",
|
|
14
|
+
"update-refs",
|
|
15
|
+
"capabilities",
|
|
16
|
+
"trace",
|
|
17
|
+
"graphql",
|
|
18
|
+
]);
|
|
12
19
|
|
|
13
20
|
function findCommandArg(argv: readonly string[]): string | undefined {
|
|
14
21
|
const args = argv.slice(2);
|
package/src/pipeline/runCli.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { GlobalFlags } from "@canonical/cli-core";
|
|
2
2
|
import { CommanderError } from "commander";
|
|
3
|
+
import { commands as graphqlCommands } from "../domains/graphql/index.js";
|
|
4
|
+
import { buildCapabilitiesCommand } from "../domains/llm/index.js";
|
|
3
5
|
import { commands as refsCommands } from "../domains/refs/index.js";
|
|
4
6
|
import { commands as setupCommands } from "../domains/setup/index.js";
|
|
5
7
|
import type { PragmaContext } from "../domains/shared/context.js";
|
|
6
8
|
import type { PragmaRuntime } from "../domains/shared/runtime.js";
|
|
7
9
|
import { bootPragma } from "../domains/shared/runtime.js";
|
|
10
|
+
import { commands as traceCommands } from "../domains/trace/index.js";
|
|
8
11
|
import { PragmaError } from "../error/index.js";
|
|
9
12
|
import collectCommands from "./collectCommands.js";
|
|
10
13
|
import createProgram from "./createProgram.js";
|
|
@@ -78,6 +81,7 @@ async function handleRootHelp(globalFlags: GlobalFlags): Promise<void> {
|
|
|
78
81
|
store: {} as PragmaRuntime["store"],
|
|
79
82
|
config: { tier: undefined, channel: "normal" },
|
|
80
83
|
cwd: process.cwd(),
|
|
84
|
+
packages: [],
|
|
81
85
|
dispose: () => {},
|
|
82
86
|
globalFlags,
|
|
83
87
|
interactive: runInteractiveCommand,
|
|
@@ -137,11 +141,18 @@ async function runStoreSkip(
|
|
|
137
141
|
store: {} as PragmaRuntime["store"],
|
|
138
142
|
config: { tier: undefined, channel: "normal" },
|
|
139
143
|
cwd: process.cwd(),
|
|
144
|
+
packages: [],
|
|
140
145
|
dispose: () => {},
|
|
141
146
|
globalFlags,
|
|
142
147
|
interactive: runInteractiveCommand,
|
|
143
148
|
};
|
|
144
|
-
const commands = [
|
|
149
|
+
const commands = [
|
|
150
|
+
...setupCommands(),
|
|
151
|
+
...refsCommands(),
|
|
152
|
+
...traceCommands(),
|
|
153
|
+
...graphqlCommands(),
|
|
154
|
+
buildCapabilitiesCommand(),
|
|
155
|
+
];
|
|
145
156
|
const program = createProgram(commands, stubCtx);
|
|
146
157
|
|
|
147
158
|
try {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTL fixtures for graphql domain tests.
|
|
3
|
+
*
|
|
4
|
+
* Three compile outcomes: a clean ontology (no diagnostics), an ontology
|
|
5
|
+
* with an unresolvable field-name collision (M001 error diagnostic, schema
|
|
6
|
+
* still composes), and an ontology whose reserved `__` field name fails
|
|
7
|
+
* schema composition entirely (C003 → CompilationError).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Namespace used by all graphql fixtures. */
|
|
11
|
+
export const EX_NAMESPACE = "http://example.org/";
|
|
12
|
+
|
|
13
|
+
/** `--prefix` entry registering {@link EX_NAMESPACE}. */
|
|
14
|
+
export const EX_PREFIX_ENTRY = `ex=${EX_NAMESPACE}`;
|
|
15
|
+
|
|
16
|
+
const prefixBlock = `@prefix ex: <${EX_NAMESPACE}> .
|
|
17
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
18
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
19
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .`;
|
|
20
|
+
|
|
21
|
+
/** Compiles to `type Thing` with zero diagnostics. */
|
|
22
|
+
export const GRAPHQL_CLEAN_TTL = `${prefixBlock}
|
|
23
|
+
|
|
24
|
+
ex:Thing a owl:Class ;
|
|
25
|
+
rdfs:label "Thing" .
|
|
26
|
+
|
|
27
|
+
ex:name a owl:DatatypeProperty ;
|
|
28
|
+
rdfs:domain ex:Thing ;
|
|
29
|
+
rdfs:range xsd:string ;
|
|
30
|
+
rdfs:label "name" .
|
|
31
|
+
|
|
32
|
+
ex:widget a ex:Thing ;
|
|
33
|
+
ex:name "Widget" .
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Produces an M001 error diagnostic (three properties collapse to
|
|
38
|
+
* `Thing.name` and the namespace-prefixed rename collides too), but the
|
|
39
|
+
* schema still composes — no CompilationError.
|
|
40
|
+
*/
|
|
41
|
+
export const GRAPHQL_ERROR_TTL = `${prefixBlock}
|
|
42
|
+
|
|
43
|
+
ex:Thing a owl:Class ;
|
|
44
|
+
rdfs:label "Thing" .
|
|
45
|
+
|
|
46
|
+
ex:name a owl:DatatypeProperty ;
|
|
47
|
+
rdfs:domain ex:Thing ;
|
|
48
|
+
rdfs:range xsd:string .
|
|
49
|
+
|
|
50
|
+
ex:hasName a owl:DatatypeProperty ;
|
|
51
|
+
rdfs:domain ex:Thing ;
|
|
52
|
+
rdfs:range xsd:string .
|
|
53
|
+
|
|
54
|
+
ex:isName a owl:DatatypeProperty ;
|
|
55
|
+
rdfs:domain ex:Thing ;
|
|
56
|
+
rdfs:range xsd:string .
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Fails schema composition (C003): `__bad` survives name sanitization but
|
|
61
|
+
* `__` is reserved by GraphQL introspection, so compile() throws
|
|
62
|
+
* CompilationError.
|
|
63
|
+
*/
|
|
64
|
+
export const GRAPHQL_FATAL_TTL = `${prefixBlock}
|
|
65
|
+
|
|
66
|
+
ex:Thing a owl:Class ;
|
|
67
|
+
rdfs:label "Thing" .
|
|
68
|
+
|
|
69
|
+
ex:__bad a owl:DatatypeProperty ;
|
|
70
|
+
rdfs:domain ex:Thing ;
|
|
71
|
+
rdfs:range xsd:string .
|
|
72
|
+
`;
|
package/src/testing/index.ts
CHANGED
|
@@ -3,6 +3,13 @@ export type { CommandResult } from "./cli.js";
|
|
|
3
3
|
export { runCommand } from "./cli.js";
|
|
4
4
|
export { default as createTestMcpClient } from "./createTestMcpClient.js";
|
|
5
5
|
export { DS_ALL_TTL, DS_ONTOLOGY_TTL, DS_TIERS_TTL } from "./dsFixtures.js";
|
|
6
|
+
export {
|
|
7
|
+
EX_NAMESPACE,
|
|
8
|
+
EX_PREFIX_ENTRY,
|
|
9
|
+
GRAPHQL_CLEAN_TTL,
|
|
10
|
+
GRAPHQL_ERROR_TTL,
|
|
11
|
+
GRAPHQL_FATAL_TTL,
|
|
12
|
+
} from "./graphqlFixtures.js";
|
|
6
13
|
export type { PragmaTestStoreOptions } from "./store.js";
|
|
7
14
|
export { createTestStore } from "./store.js";
|
|
8
15
|
export type { TestMcpClientResult } from "./types.js";
|
|
@@ -41,17 +41,23 @@ function parseEnvelope(
|
|
|
41
41
|
// ---------------------------------------------------------------------------
|
|
42
42
|
|
|
43
43
|
describe("capabilities", () => {
|
|
44
|
-
it("returns tool
|
|
44
|
+
it("returns enriched tool catalog with conventions", async () => {
|
|
45
45
|
const res = await client.callTool({ name: "capabilities", arguments: {} });
|
|
46
46
|
const body = parseEnvelope(res);
|
|
47
47
|
expect(body.ok).toBe(true);
|
|
48
48
|
const data = body.data as {
|
|
49
|
-
|
|
49
|
+
version: string;
|
|
50
|
+
conventions: Record<string, string>;
|
|
51
|
+
tools: { name: string; category: string; use_when: string }[];
|
|
50
52
|
counts: Record<string, number>;
|
|
51
53
|
};
|
|
52
|
-
|
|
53
|
-
expect(
|
|
54
|
-
expect(
|
|
54
|
+
const toolNames = data.tools.map((t) => t.name);
|
|
55
|
+
expect(toolNames).toContain("block_list");
|
|
56
|
+
expect(toolNames).toContain("capabilities");
|
|
57
|
+
expect(data.tools.every((t) => t.use_when.length > 0)).toBe(true);
|
|
58
|
+
expect(data.counts.total).toBe(29);
|
|
59
|
+
expect(data.conventions).toBeDefined();
|
|
60
|
+
expect(data.version).toBeDefined();
|
|
55
61
|
});
|
|
56
62
|
});
|
|
57
63
|
|