@canonical/pragma-cli 0.30.0 → 0.31.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 +64 -35
- package/dist/pragma +0 -0
- package/package.json +15 -13
- package/src/completions/constants.ts +7 -0
- package/src/completions/handleQuery.test.ts +32 -0
- package/src/completions/handleQuery.ts +20 -1
- package/src/completions/queryCompletions.test.ts +5 -0
- package/src/completions/queryCompletions.ts +17 -3
- package/src/completions/querySocket.test.ts +31 -0
- package/src/completions/querySocket.ts +36 -9
- package/src/config/parseConfigValues.ts +2 -0
- package/src/config/readConfigLayers.test.ts +2 -0
- package/src/config/readConfigLayers.ts +3 -0
- package/src/config/types.ts +7 -0
- package/src/constants.ts +3 -1
- package/src/domains/block/commands/sample.ts +2 -1
- package/src/domains/block/formatters/list.test.ts +3 -3
- package/src/domains/block/formatters/lookup.test.ts +5 -5
- package/src/domains/block/orchestration/enrichBlocks.ts +6 -3
- package/src/domains/block/stories.ts +9 -3
- package/src/domains/config/commands/channel.test.ts +16 -0
- package/src/domains/config/commands/channel.ts +14 -1
- package/src/domains/config/commands/framework.test.ts +14 -0
- package/src/domains/config/commands/framework.ts +13 -1
- package/src/domains/config/commands/tier.test.ts +7 -0
- package/src/domains/config/commands/tier.ts +14 -1
- package/src/domains/config/operations/validateTier.test.ts +9 -0
- package/src/domains/config/operations/validateTier.ts +10 -2
- package/src/domains/create/generatorPack/bundled.ts +49 -0
- package/src/domains/create/generatorPack/compileGeneratorPack.test.ts +159 -0
- package/src/domains/create/generatorPack/compileGeneratorPack.ts +312 -0
- package/src/domains/create/index.ts +13 -7
- package/src/domains/create/mcp/specs.ts +6 -161
- package/src/domains/create/renderGeneratorUi.test.ts +103 -0
- package/src/domains/create/renderGeneratorUi.ts +65 -0
- package/src/domains/doctor/formatters/doctor.test.ts +50 -2
- package/src/domains/doctor/formatters/doctor.ts +90 -38
- package/src/domains/doctor/operations/checks/checkMcpCommands.ts +9 -6
- package/src/domains/doctor/operations/checks/checkPackageRefs.ts +30 -12
- package/src/domains/doctor/operations/checks.test.ts +6 -4
- package/src/domains/doctor/operations/types.ts +23 -1
- package/src/domains/graph/commands/inspect.test.ts +2 -2
- package/src/domains/graph/commands/query.test.ts +5 -3
- package/src/domains/graph/formatters/inspect.ts +7 -7
- package/src/domains/graph/formatters/query.test.ts +87 -0
- package/src/domains/graph/formatters/query.ts +42 -5
- package/src/domains/graph/operations/inspectUri.test.ts +5 -5
- package/src/domains/graphql/commands/serve.test.ts +12 -6
- package/src/domains/graphql/commands/serve.ts +16 -6
- package/src/domains/graphql/helpers/parsePrefixes.test.ts +3 -3
- package/src/domains/graphql/helpers/parsePrefixes.ts +3 -3
- package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +9 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.ts +24 -3
- package/src/domains/graphql/operations/compileSchema.test.ts +2 -2
- package/src/domains/graphql/operations/createSchemaServer.test.ts +2 -2
- package/src/domains/graphql/operations/ensureSchemaArtifact.test.ts +167 -0
- package/src/domains/graphql/operations/ensureSchemaArtifact.ts +178 -0
- package/src/domains/graphql/operations/index.ts +5 -0
- package/src/domains/info/formatters/upgrade.test.ts +7 -4
- package/src/domains/info/formatters/upgrade.ts +3 -1
- package/src/domains/info/operations/collectEntityCounts.test.ts +156 -0
- package/src/domains/info/operations/collectEntityCounts.ts +123 -0
- package/src/domains/info/operations/index.ts +1 -0
- package/src/domains/info/types.ts +13 -0
- package/src/domains/llm/capabilities.test.ts +23 -3
- package/src/domains/llm/commands/capabilities.ts +12 -3
- package/src/domains/llm/commands/llm.ts +5 -1
- package/src/domains/llm/data/commandReference.ts +20 -11
- package/src/domains/llm/data/decisionTrees.ts +10 -5
- package/src/domains/llm/data/toolCatalog.ts +49 -18
- package/src/domains/llm/formatters/orientation.ts +5 -1
- package/src/domains/llm/llmCommand.test.ts +11 -3
- package/src/domains/llm/mcp/specs.ts +3 -4
- package/src/domains/llm/operations/collectContext.test.ts +64 -0
- package/src/domains/llm/operations/collectContext.ts +7 -17
- package/src/domains/modifier/commands/sample.ts +2 -1
- package/src/domains/modifier/operations/lookup.ts +5 -3
- package/src/domains/modifier/stories.ts +9 -0
- package/src/domains/ontology/commands/list.test.ts +5 -3
- package/src/domains/ontology/commands/show.test.ts +85 -9
- package/src/domains/ontology/formatters/index.ts +1 -0
- package/src/domains/ontology/formatters/list.ts +37 -12
- package/src/domains/ontology/formatters/show.ts +358 -67
- package/src/domains/ontology/helpers/buildClassTree.ts +89 -0
- package/src/domains/ontology/helpers/completeClassNames.ts +43 -0
- package/src/domains/ontology/helpers/expandOntologyIris.ts +79 -0
- package/src/domains/ontology/helpers/index.ts +14 -0
- package/src/domains/ontology/helpers/queryClasses.ts +32 -16
- package/src/domains/ontology/helpers/queryProperties.ts +39 -6
- package/src/domains/ontology/helpers/queryTboxFacts.ts +160 -0
- package/src/domains/ontology/operations/listOntologies.test.ts +80 -3
- package/src/domains/ontology/operations/listOntologies.ts +126 -30
- package/src/domains/ontology/operations/showOntology.test.ts +131 -12
- package/src/domains/ontology/operations/showOntology.ts +289 -7
- package/src/domains/ontology/operations/showOntologyRaw.test.ts +4 -2
- package/src/domains/ontology/stories.ts +53 -8
- package/src/domains/refs/operations/updateRefs.ts +0 -1
- package/src/domains/setup/commands/index.ts +1 -0
- package/src/domains/setup/commands/setup.ts +70 -0
- package/src/domains/setup/index.ts +7 -3
- package/src/domains/setup/operations/setupLsp.test.ts +3 -2
- package/src/domains/setup/operations/setupLsp.ts +7 -2
- package/src/domains/shared/bootStore.bareCore.test.ts +63 -0
- package/src/domains/shared/bootStore.test.ts +82 -0
- package/src/domains/shared/bootStore.ts +56 -20
- package/src/domains/shared/emptyErrorRecovery.test.ts +23 -26
- package/src/domains/shared/extractLocalName.test.ts +3 -3
- package/src/domains/shared/formatters.ts +23 -2
- package/src/domains/shared/listTiers.ts +40 -0
- package/src/domains/shared/loaders/bundledLoader.ts +48 -0
- package/src/domains/shared/loaders/gitLoader.ts +1 -2
- package/src/domains/shared/loaders/localLoader.ts +2 -18
- package/src/domains/shared/loaders/readPackageDir.test.ts +58 -0
- package/src/domains/shared/loaders/readPackageDir.ts +46 -8
- package/src/domains/shared/lookupMany.test.ts +15 -0
- package/src/domains/shared/lookupMany.ts +22 -6
- package/src/domains/shared/namespaces.ts +13 -5
- package/src/domains/shared/parseSampleCount.test.ts +47 -0
- package/src/domains/shared/parseSampleCount.ts +45 -0
- package/src/domains/shared/prefixes.test.ts +211 -0
- package/src/domains/shared/prefixes.ts +182 -15
- package/src/domains/shared/renderers.ts +5 -5
- package/src/domains/shared/resolveLookupExitCode.test.ts +48 -0
- package/src/domains/shared/resolveLookupExitCode.ts +42 -0
- package/src/domains/shared/semanticPackage.test.ts +89 -0
- package/src/domains/shared/semanticPackage.ts +17 -2
- package/src/domains/shared/stories/compileLookupCommand.ts +3 -1
- package/src/domains/shared/stories/compileLookupTool.ts +1 -1
- package/src/domains/shared/stories/pack/applyPackFilters.test.ts +49 -0
- package/src/domains/shared/stories/pack/applyPackFilters.ts +46 -11
- package/src/domains/shared/stories/pack/applyPackSearch.test.ts +57 -0
- package/src/domains/shared/stories/pack/applyPackSearch.ts +41 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +30 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.ts +75 -1
- package/src/domains/shared/stories/pack/bundled/index.ts +23 -0
- package/src/domains/shared/stories/pack/bundled/standardPack.ts +164 -0
- package/src/domains/shared/stories/pack/bundled/tierPack.ts +50 -0
- package/src/domains/shared/stories/pack/collectPackStories.test.ts +305 -7
- package/src/domains/shared/stories/pack/collectPackStories.ts +90 -8
- package/src/domains/shared/stories/pack/compilePackCommands.ts +17 -7
- package/src/domains/shared/stories/pack/compilePackStories.test.ts +607 -2
- package/src/domains/shared/stories/pack/compilePackStories.ts +544 -73
- package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +20 -8
- package/src/domains/shared/stories/pack/index.ts +14 -0
- package/src/domains/shared/stories/pack/reservedVerbs.test.ts +213 -0
- package/src/domains/shared/stories/pack/reservedVerbs.ts +170 -0
- package/src/domains/shared/stories/pack/standardParity.test.ts +293 -220
- package/src/domains/shared/stories/pack/types.ts +123 -3
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +502 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +475 -24
- package/src/domains/shared/stories/types.ts +9 -1
- package/src/domains/shared/types/index.ts +5 -9
- package/src/domains/shared/types/ontology.ts +119 -24
- package/src/domains/shared/types/standard.ts +9 -52
- package/src/domains/token/commands/lookup.test.ts +8 -0
- package/src/domains/token/commands/lookup.ts +12 -0
- package/src/domains/token/commands/sample.ts +2 -1
- package/src/domains/token/featureFlag.ts +17 -0
- package/src/domains/token/index.ts +5 -0
- package/src/domains/token/mcp/specs.ts +13 -1
- package/src/domains/trace/commands/resolveTraceLimit.test.ts +31 -0
- package/src/domains/trace/commands/show.ts +30 -4
- package/src/index.ts +1 -13
- package/src/mcp/registerResources.test.ts +2 -2
- package/src/mcp/resources/pickPrimaryType.test.ts +5 -5
- package/src/mcp/tools/index.ts +18 -10
- package/src/mcp/tools/registerTools.test.ts +106 -30
- package/src/pipeline/collectCommands.test.ts +151 -1
- package/src/pipeline/collectCommands.ts +34 -19
- package/src/pipeline/createProgram.test.ts +5 -1
- package/src/pipeline/createProgram.ts +2 -2
- package/src/pipeline/firstRun.test.ts +80 -0
- package/src/pipeline/firstRun.ts +99 -0
- package/src/pipeline/parseGlobalFlags.test.ts +102 -1
- package/src/pipeline/parseGlobalFlags.ts +98 -9
- package/src/pipeline/resolveCommandKind.test.ts +12 -0
- package/src/pipeline/resolveCommandKind.ts +4 -0
- package/src/pipeline/rootHelp.test.ts +87 -0
- package/src/pipeline/rootHelp.ts +265 -0
- package/src/pipeline/runCli.orchestration.test.ts +28 -12
- package/src/pipeline/runCli.test.ts +17 -4
- package/src/pipeline/runCli.ts +162 -19
- package/src/testing/cli.ts +30 -2
- package/src/testing/dsFixtures.ts +21 -4
- package/src/testing/index.ts +1 -4
- package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +4 -4
- package/src/testing/integration/cli-user-stories.test.ts +63 -0
- package/src/testing/integration/cross-binary-byte-equality.test.ts +2 -2
- package/src/testing/integration/edge-cases.test.ts +62 -50
- package/src/testing/integration/executor-execution.test.ts +6 -4
- package/src/testing/integration/executor-golden.test.ts +2 -2
- package/src/testing/integration/mcp-surface.test.ts +40 -15
- package/src/testing/integration/parity.test.ts +119 -70
- package/src/testing/setupXdgIsolation.ts +16 -5
- package/src/testing/standardParityFixtures.ts +26 -83
- package/src/testing/store.ts +4 -4
- package/src/domains/create/commands/component.test.ts +0 -166
- package/src/domains/create/commands/component.ts +0 -123
- package/src/domains/create/commands/index.ts +0 -3
- package/src/domains/create/commands/package.test.ts +0 -35
- package/src/domains/create/commands/package.ts +0 -21
- package/src/domains/create/generators.ts +0 -8
- package/src/domains/standard/commands/categories.test.ts +0 -70
- package/src/domains/standard/commands/categories.ts +0 -48
- package/src/domains/standard/commands/index.ts +0 -6
- package/src/domains/standard/commands/list.test.ts +0 -105
- package/src/domains/standard/commands/list.ts +0 -11
- package/src/domains/standard/commands/lookup.test.ts +0 -135
- package/src/domains/standard/commands/lookup.ts +0 -14
- package/src/domains/standard/commands/sample.ts +0 -57
- package/src/domains/standard/formatters/categories.test.ts +0 -44
- package/src/domains/standard/formatters/categories.ts +0 -38
- package/src/domains/standard/formatters/index.ts +0 -10
- package/src/domains/standard/formatters/list.test.ts +0 -169
- package/src/domains/standard/formatters/list.ts +0 -184
- package/src/domains/standard/formatters/lookup.test.ts +0 -95
- package/src/domains/standard/formatters/lookup.ts +0 -101
- package/src/domains/standard/formatters/sample.ts +0 -15
- package/src/domains/standard/formatters/types.ts +0 -31
- package/src/domains/standard/index.ts +0 -40
- package/src/domains/standard/mcp/index.ts +0 -2
- package/src/domains/standard/mcp/specs.ts +0 -89
- package/src/domains/standard/operations/categories.test.ts +0 -61
- package/src/domains/standard/operations/categories.ts +0 -38
- package/src/domains/standard/operations/index.ts +0 -6
- package/src/domains/standard/operations/list.test.ts +0 -75
- package/src/domains/standard/operations/list.ts +0 -64
- package/src/domains/standard/operations/lookup.test.ts +0 -58
- package/src/domains/standard/operations/lookup.ts +0 -151
- package/src/domains/standard/operations/sample.ts +0 -35
- package/src/domains/standard/orchestration/buildStandardFilters.ts +0 -11
- package/src/domains/standard/orchestration/index.ts +0 -4
- package/src/domains/standard/orchestration/resolveStandardList.ts +0 -45
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +0 -33
- package/src/domains/standard/orchestration/standardEmptyError.test.ts +0 -33
- package/src/domains/standard/orchestration/standardEmptyError.ts +0 -29
- package/src/domains/standard/standardConfig.ts +0 -42
- package/src/domains/standard/stories.test.ts +0 -24
- package/src/domains/standard/stories.ts +0 -151
- package/src/domains/standard/types.ts +0 -15
- package/src/domains/tier/commands/index.ts +0 -3
- package/src/domains/tier/commands/list.test.ts +0 -67
- package/src/domains/tier/commands/list.ts +0 -9
- package/src/domains/tier/formatters/index.ts +0 -3
- package/src/domains/tier/formatters/list.test.ts +0 -33
- package/src/domains/tier/formatters/list.ts +0 -45
- package/src/domains/tier/index.ts +0 -17
- package/src/domains/tier/mcp/index.ts +0 -2
- package/src/domains/tier/mcp/specs.ts +0 -12
- package/src/domains/tier/operations/index.ts +0 -3
- package/src/domains/tier/operations/list.test.ts +0 -32
- package/src/domains/tier/operations/list.ts +0 -33
- package/src/domains/tier/stories.test.ts +0 -22
- package/src/domains/tier/stories.ts +0 -52
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Store } from "@canonical/ke";
|
|
2
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
3
|
+
import { createTestStore, DS_ALL_TTL } from "#testing";
|
|
4
|
+
import type { FilterConfig } from "../../shared/types/index.js";
|
|
5
|
+
import { TOKEN_READ_SURFACE_ENABLED } from "../../token/featureFlag.js";
|
|
6
|
+
import { renderLlmOrientation } from "../formatters/index.js";
|
|
7
|
+
import type { LlmData } from "../types.js";
|
|
8
|
+
import collectContext from "./collectContext.js";
|
|
9
|
+
|
|
10
|
+
let store: Store;
|
|
11
|
+
let cleanup: () => void;
|
|
12
|
+
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
const result = await createTestStore({ ttl: DS_ALL_TTL });
|
|
15
|
+
store = result.store;
|
|
16
|
+
cleanup = result.cleanup;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterAll(() => cleanup());
|
|
20
|
+
|
|
21
|
+
const config: FilterConfig = { tier: undefined, channel: "prerelease" };
|
|
22
|
+
|
|
23
|
+
/** Extract the `## Context` data lines from a rendered orientation doc. */
|
|
24
|
+
function contextBlock(rendered: string): string {
|
|
25
|
+
const lines = rendered.split("\n");
|
|
26
|
+
const start = lines.indexOf("## Context");
|
|
27
|
+
const block: string[] = [];
|
|
28
|
+
for (let i = start + 1; i < lines.length && lines[i] !== ""; i++) {
|
|
29
|
+
block.push(lines[i] ?? "");
|
|
30
|
+
}
|
|
31
|
+
return block.join("\n");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe("collectContext", () => {
|
|
35
|
+
it("assembles counts and namespaces from the store", async () => {
|
|
36
|
+
const ctx = await collectContext(store, config);
|
|
37
|
+
|
|
38
|
+
expect(ctx.tier).toBeUndefined();
|
|
39
|
+
expect(ctx.channel).toBe("prerelease");
|
|
40
|
+
expect(ctx.counts.blocks).toBeGreaterThan(0);
|
|
41
|
+
expect(ctx.counts.standards).toBeGreaterThan(0);
|
|
42
|
+
expect(ctx.counts.modifierFamilies).toBeGreaterThan(0);
|
|
43
|
+
expect(ctx.counts.tokens).toBeGreaterThan(0);
|
|
44
|
+
expect(ctx.namespaces.length).toBeGreaterThan(0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("renders a stable `## Context` block", async () => {
|
|
48
|
+
const data: LlmData = {
|
|
49
|
+
context: await collectContext(store, config),
|
|
50
|
+
decisionTrees: [],
|
|
51
|
+
commandReference: [],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// The token count only renders while the token read surface is enabled.
|
|
55
|
+
const tokenSegment = TOKEN_READ_SURFACE_ENABLED ? ", 2 tokens" : "";
|
|
56
|
+
expect(contextBlock(renderLlmOrientation(data))).toBe(
|
|
57
|
+
[
|
|
58
|
+
"tier: (none) | channel: prerelease",
|
|
59
|
+
`data: 5 blocks, 3 standards, 2 modifier families${tokenSegment}`,
|
|
60
|
+
"namespaces: cs, ds",
|
|
61
|
+
].join("\n"),
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import type { Store } from "@canonical/ke";
|
|
2
|
-
import {
|
|
3
|
-
import { listModifiers } from "../../modifier/operations/index.js";
|
|
2
|
+
import { collectEntityCounts } from "../../info/operations/index.js";
|
|
4
3
|
import { listOntologies } from "../../ontology/operations/index.js";
|
|
5
4
|
import { resolveTierChain } from "../../shared/filters/buildTierFilter.js";
|
|
6
5
|
import type { FilterConfig } from "../../shared/types/index.js";
|
|
7
|
-
import { listStandards } from "../../standard/operations/index.js";
|
|
8
|
-
import { listTokens } from "../../token/operations/index.js";
|
|
9
6
|
import type { LlmContext } from "../types.js";
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* Collects dynamic context for the `pragma llm` orientation output.
|
|
13
10
|
*
|
|
14
|
-
* Queries the store in parallel for
|
|
15
|
-
* ontology
|
|
11
|
+
* Queries the store in parallel for entity counts (via
|
|
12
|
+
* {@link collectEntityCounts}) and ontology namespaces, and combines them
|
|
13
|
+
* with tier/channel config state.
|
|
16
14
|
*
|
|
17
15
|
* @note Queries ke store
|
|
18
16
|
*
|
|
@@ -24,11 +22,8 @@ export default async function collectContext(
|
|
|
24
22
|
store: Store,
|
|
25
23
|
config: FilterConfig,
|
|
26
24
|
): Promise<LlmContext> {
|
|
27
|
-
const [
|
|
28
|
-
|
|
29
|
-
listStandards(store),
|
|
30
|
-
listModifiers(store),
|
|
31
|
-
listTokens(store),
|
|
25
|
+
const [counts, ontologies] = await Promise.all([
|
|
26
|
+
collectEntityCounts(store, config),
|
|
32
27
|
listOntologies(store),
|
|
33
28
|
]);
|
|
34
29
|
|
|
@@ -36,12 +31,7 @@ export default async function collectContext(
|
|
|
36
31
|
tier: config.tier,
|
|
37
32
|
tierChain: resolveTierChain(config.tier),
|
|
38
33
|
channel: config.channel,
|
|
39
|
-
counts
|
|
40
|
-
blocks: blocks.length,
|
|
41
|
-
standards: standards.length,
|
|
42
|
-
modifierFamilies: modifiers.length,
|
|
43
|
-
tokens: tokens.length,
|
|
44
|
-
},
|
|
34
|
+
counts,
|
|
45
35
|
namespaces: ontologies.map((o) => o.prefix),
|
|
46
36
|
};
|
|
47
37
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@canonical/cli-core";
|
|
12
12
|
import type { PragmaContext } from "../../shared/context.js";
|
|
13
13
|
import { selectFormatter } from "../../shared/formatters.js";
|
|
14
|
+
import parseSampleCount from "../../shared/parseSampleCount.js";
|
|
14
15
|
import type { ModifierFamily, SampleOutput } from "../../shared/types/index.js";
|
|
15
16
|
import { sampleFormatters } from "../formatters/index.js";
|
|
16
17
|
import { sampleModifiers } from "../operations/index.js";
|
|
@@ -37,7 +38,7 @@ export default function sampleCommand(ctx: PragmaContext): CommandDefinition {
|
|
|
37
38
|
examples: ["pragma modifier sample", "pragma modifier sample --count 3"],
|
|
38
39
|
},
|
|
39
40
|
async execute(params) {
|
|
40
|
-
const count =
|
|
41
|
+
const count = parseSampleCount(params.count);
|
|
41
42
|
const result = await sampleModifiers(ctx.store, count);
|
|
42
43
|
|
|
43
44
|
const output: SampleOutput<ModifierFamily> = {
|
|
@@ -28,7 +28,7 @@ export default async function lookupModifier(
|
|
|
28
28
|
|
|
29
29
|
const result = await store.query(
|
|
30
30
|
buildQuery(`
|
|
31
|
-
SELECT ?family (GROUP_CONCAT(DISTINCT ?valueName; separator="|") AS ?values)
|
|
31
|
+
SELECT ?family ?familyName (GROUP_CONCAT(DISTINCT ?valueName; separator="|") AS ?values)
|
|
32
32
|
WHERE {
|
|
33
33
|
?family a ${P.ds}ModifierFamily ;
|
|
34
34
|
${P.ds}name ?familyName .
|
|
@@ -39,7 +39,7 @@ export default async function lookupModifier(
|
|
|
39
39
|
${P.ds}name ?valueName .
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
-
GROUP BY ?family
|
|
42
|
+
GROUP BY ?family ?familyName
|
|
43
43
|
`),
|
|
44
44
|
);
|
|
45
45
|
|
|
@@ -61,7 +61,9 @@ export default async function lookupModifier(
|
|
|
61
61
|
const b = result.bindings[0] as (typeof result.bindings)[number];
|
|
62
62
|
return {
|
|
63
63
|
uri: (b.family ?? "") as URI,
|
|
64
|
-
name,
|
|
64
|
+
// Return the canonical stored name, not the raw user query (which may
|
|
65
|
+
// differ in casing).
|
|
66
|
+
name: b.familyName ?? name,
|
|
65
67
|
values: b.values ? b.values.split("|").filter(Boolean) : [],
|
|
66
68
|
};
|
|
67
69
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { createListView, createLookupView } from "#tui";
|
|
10
|
+
import { PragmaError } from "../../error/index.js";
|
|
10
11
|
import type { LookupStory, ReadStory } from "../shared/stories/index.js";
|
|
11
12
|
import type { ModifierFamily } from "../shared/types/index.js";
|
|
12
13
|
import {
|
|
@@ -67,6 +68,14 @@ export const modifierLookupStory: LookupStory<ModifierFamily, ModifierFamily> =
|
|
|
67
68
|
},
|
|
68
69
|
toFmtInput: (family) => family,
|
|
69
70
|
formatters: lookupFormatters,
|
|
71
|
+
emptyNamesError: () =>
|
|
72
|
+
PragmaError.invalidInput("names", "(empty)", {
|
|
73
|
+
recovery: {
|
|
74
|
+
message: "List available modifier families.",
|
|
75
|
+
cli: "pragma modifier list",
|
|
76
|
+
mcp: { tool: "modifier_list" },
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
70
79
|
renderInk: (result) =>
|
|
71
80
|
createLookupView({
|
|
72
81
|
results: result.results,
|
|
@@ -52,8 +52,10 @@ describe("ontology list command", () => {
|
|
|
52
52
|
const { text } = await executeOutput(cmd, {}, ctx);
|
|
53
53
|
|
|
54
54
|
expect(text).toContain("ds");
|
|
55
|
-
expect(text).toContain("classes
|
|
56
|
-
expect(text).toContain("
|
|
55
|
+
expect(text).toContain("classes");
|
|
56
|
+
expect(text).toContain("relations");
|
|
57
|
+
expect(text).toContain("attributes");
|
|
58
|
+
expect(text).toContain("Next: pragma ontology show <prefix>");
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
it("renders llm output", async () => {
|
|
@@ -65,7 +67,7 @@ describe("ontology list command", () => {
|
|
|
65
67
|
|
|
66
68
|
expect(text).toContain("## Ontologies");
|
|
67
69
|
expect(text).toContain("**ds:**");
|
|
68
|
-
expect(text).toContain("
|
|
70
|
+
expect(text).toContain("relations");
|
|
69
71
|
});
|
|
70
72
|
|
|
71
73
|
it("renders json output", async () => {
|
|
@@ -3,7 +3,7 @@ import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
|
3
3
|
import createTestRuntime from "../../../testing/helpers/createTestRuntime.js";
|
|
4
4
|
import type { PragmaContext } from "../../shared/context.js";
|
|
5
5
|
import type { PragmaRuntime } from "../../shared/runtime.js";
|
|
6
|
-
import type {
|
|
6
|
+
import type { OntologyShowInput } from "../formatters/index.js";
|
|
7
7
|
import buildShowCommand from "./show.js";
|
|
8
8
|
|
|
9
9
|
let runtime: PragmaRuntime;
|
|
@@ -41,10 +41,69 @@ describe("ontology show command", () => {
|
|
|
41
41
|
const cmd = buildShowCommand(ctx);
|
|
42
42
|
const { value } = await executeOutput(cmd, { prefix: "ds" }, ctx);
|
|
43
43
|
|
|
44
|
-
const
|
|
45
|
-
expect(
|
|
46
|
-
expect(
|
|
47
|
-
|
|
44
|
+
const { ontology } = value as OntologyShowInput;
|
|
45
|
+
expect(ontology.prefix).toBe("ds");
|
|
46
|
+
expect(ontology.classes.length).toBeGreaterThan(0);
|
|
47
|
+
const propertyCount =
|
|
48
|
+
ontology.classes.reduce((n, c) => n + c.properties.length, 0) +
|
|
49
|
+
ontology.unattached.length;
|
|
50
|
+
expect(propertyCount).toBeGreaterThan(0);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("deep-dives into a class via the class param", async () => {
|
|
54
|
+
const ctx = makeCtx();
|
|
55
|
+
const cmd = buildShowCommand(ctx);
|
|
56
|
+
const { value, text } = await executeOutput(
|
|
57
|
+
cmd,
|
|
58
|
+
{ prefix: "ds", class: "Component" },
|
|
59
|
+
ctx,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const { ontology } = value as OntologyShowInput;
|
|
63
|
+
expect(ontology.focus?.iri).toBe("ds:Component");
|
|
64
|
+
expect(text).toContain("Component");
|
|
65
|
+
expect(text).toContain("extends:");
|
|
66
|
+
// Follow-up querying: the deep dive hands over runnable SPARQL.
|
|
67
|
+
expect(text).toContain(
|
|
68
|
+
"SELECT ?instance WHERE { ?instance a ds:Component }",
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("hides attributes by default and shows them with --properties", async () => {
|
|
73
|
+
const ctx = makeCtx();
|
|
74
|
+
const cmd = buildShowCommand(ctx);
|
|
75
|
+
|
|
76
|
+
const bare = await executeOutput(cmd, { prefix: "ds" }, ctx);
|
|
77
|
+
// Attributes render as `label: range` — absent by default.
|
|
78
|
+
expect(bare.text).not.toContain(": xsd:");
|
|
79
|
+
// hasModifierFamily is an object property (relation) — always shown.
|
|
80
|
+
expect(bare.text).toContain("hasModifierFamily");
|
|
81
|
+
|
|
82
|
+
const withProps = await executeOutput(
|
|
83
|
+
cmd,
|
|
84
|
+
{ prefix: "ds", properties: true },
|
|
85
|
+
ctx,
|
|
86
|
+
);
|
|
87
|
+
expect(withProps.text).toContain(": xsd:");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("expands IRIs with --full-uris", async () => {
|
|
91
|
+
const ctx = makeCtx({
|
|
92
|
+
globalFlags: { llm: true, format: "text" as const, verbose: false },
|
|
93
|
+
});
|
|
94
|
+
const cmd = buildShowCommand(ctx);
|
|
95
|
+
const { value, text } = await executeOutput(
|
|
96
|
+
cmd,
|
|
97
|
+
{ prefix: "ds", fullUris: true },
|
|
98
|
+
ctx,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const { ontology } = value as OntologyShowInput;
|
|
102
|
+
const component = ontology.classes.find((c) => c.label === "Component");
|
|
103
|
+
expect(component?.iri).toBe("https://ds.canonical.com/Component");
|
|
104
|
+
expect(text).toContain("https://ds.canonical.com/Component");
|
|
105
|
+
// The seeded footer query must stay valid SPARQL: full URIs need <...>.
|
|
106
|
+
expect(text).toMatch(/\?s a <https:\/\/ds\.canonical\.com\//);
|
|
48
107
|
});
|
|
49
108
|
|
|
50
109
|
it("completes ontology prefixes", async () => {
|
|
@@ -57,13 +116,30 @@ describe("ontology show command", () => {
|
|
|
57
116
|
expect(matches).toContain("ds");
|
|
58
117
|
});
|
|
59
118
|
|
|
119
|
+
it("completes class names for --class", async () => {
|
|
120
|
+
const ctx = makeCtx();
|
|
121
|
+
const cmd = buildShowCommand(ctx);
|
|
122
|
+
const classParam = cmd.parameters.find((p) => p.name === "class");
|
|
123
|
+
const complete = classParam?.complete;
|
|
124
|
+
|
|
125
|
+
expect(complete).toBeTypeOf("function");
|
|
126
|
+
const matches = await complete?.("comp", ctx);
|
|
127
|
+
expect(matches).toContain("Component");
|
|
128
|
+
// Case-insensitive prefix match, sorted, no non-matches.
|
|
129
|
+
expect(matches?.every((m) => m.toLowerCase().startsWith("comp"))).toBe(
|
|
130
|
+
true,
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
60
134
|
it("renders plain output", async () => {
|
|
61
135
|
const ctx = makeCtx();
|
|
62
136
|
const cmd = buildShowCommand(ctx);
|
|
63
137
|
const { text } = await executeOutput(cmd, { prefix: "ds" }, ctx);
|
|
64
138
|
|
|
65
|
-
expect(text).toContain("
|
|
66
|
-
expect(text).toContain("
|
|
139
|
+
expect(text).toContain("Ontology ds:");
|
|
140
|
+
expect(text).toContain("classes");
|
|
141
|
+
// Hierarchy: children render beneath their parent with tree branches.
|
|
142
|
+
expect(text).toContain("└─");
|
|
67
143
|
});
|
|
68
144
|
|
|
69
145
|
it("renders llm output", async () => {
|
|
@@ -73,7 +149,7 @@ describe("ontology show command", () => {
|
|
|
73
149
|
const cmd = buildShowCommand(ctx);
|
|
74
150
|
const { text } = await executeOutput(cmd, { prefix: "ds" }, ctx);
|
|
75
151
|
|
|
76
|
-
expect(text).toContain("## ds:");
|
|
152
|
+
expect(text).toContain("## Ontology ds:");
|
|
77
153
|
expect(text).toContain("### Classes");
|
|
78
154
|
});
|
|
79
155
|
|
|
@@ -84,7 +160,7 @@ describe("ontology show command", () => {
|
|
|
84
160
|
const cmd = buildShowCommand(ctx);
|
|
85
161
|
const { text } = await executeOutput(cmd, { prefix: "ds" }, ctx);
|
|
86
162
|
|
|
87
|
-
const parsed = JSON.parse(text) as
|
|
163
|
+
const parsed = JSON.parse(text) as { prefix: string };
|
|
88
164
|
expect(parsed.prefix).toBe("ds");
|
|
89
165
|
});
|
|
90
166
|
|
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import compactUri from "../../shared/compactUri.js";
|
|
3
2
|
import type { Formatters } from "../../shared/formatters.js";
|
|
4
|
-
import { PREFIX_MAP } from "../../shared/prefixes.js";
|
|
5
3
|
import type { OntologySummary } from "../../shared/types/index.js";
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* Formatters for `pragma ontology list` output.
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* One line per namespace mirroring the `ontology show` summary line —
|
|
9
|
+
* name, metadata, and split counts — plus a next-command footer, so the
|
|
10
|
+
* list is the entry point of the same drill-down path
|
|
11
|
+
* (`list → show <prefix> → show <prefix> --class <Class>`).
|
|
12
|
+
*
|
|
13
|
+
* - **plain**: chalk-styled lines with counts and a dimmed footer.
|
|
14
|
+
* - **llm**: the same content as condensed Markdown bullets.
|
|
15
|
+
* - **json**: the {@link OntologySummary} array itself.
|
|
13
16
|
*/
|
|
14
17
|
const formatters: Formatters<readonly OntologySummary[]> = {
|
|
15
18
|
plain(ontologies) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
(o)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const lines = ontologies.map(
|
|
20
|
+
(o) =>
|
|
21
|
+
`${chalk.bold(prefixLabel(o))} ${o.namespace} ${chalk.dim(`— ${summaryLine(o)}`)}`,
|
|
22
|
+
);
|
|
23
|
+
lines.push("");
|
|
24
|
+
lines.push(chalk.dim("Next: pragma ontology show <prefix>"));
|
|
25
|
+
return lines.join("\n");
|
|
22
26
|
},
|
|
23
27
|
|
|
24
28
|
llm(ontologies) {
|
|
25
29
|
const lines = ["## Ontologies", ""];
|
|
26
30
|
for (const o of ontologies) {
|
|
27
31
|
lines.push(
|
|
28
|
-
`- **${o
|
|
32
|
+
`- **${prefixLabel(o)}** \`${o.namespace}\` — ${summaryLine(o)}`,
|
|
29
33
|
);
|
|
30
34
|
}
|
|
35
|
+
lines.push("");
|
|
36
|
+
lines.push("Next: `ontology show <prefix>` for the class hierarchy.");
|
|
31
37
|
return lines.join("\n");
|
|
32
38
|
},
|
|
33
39
|
|
|
@@ -37,3 +43,22 @@ const formatters: Formatters<readonly OntologySummary[]> = {
|
|
|
37
43
|
};
|
|
38
44
|
|
|
39
45
|
export default formatters;
|
|
46
|
+
|
|
47
|
+
/** `ds:` for prefixed namespaces, a placeholder for unprefixed ones. */
|
|
48
|
+
function prefixLabel(o: OntologySummary): string {
|
|
49
|
+
return o.prefix ? `${o.prefix}:` : "(no prefix)";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The same counts-and-metadata line `ontology show` leads with. */
|
|
53
|
+
function summaryLine(o: OntologySummary): string {
|
|
54
|
+
const parts = [
|
|
55
|
+
`${o.classCount} classes`,
|
|
56
|
+
`${o.relationCount} relations`,
|
|
57
|
+
`${o.attributeCount} attributes`,
|
|
58
|
+
];
|
|
59
|
+
if (o.shapeCount > 0) parts.push(`${o.shapeCount} shapes`);
|
|
60
|
+
if (o.anatomyCount > 0) parts.push(`${o.anatomyCount} anatomies`);
|
|
61
|
+
if (o.version) parts.push(`v${o.version}`);
|
|
62
|
+
if (o.title) parts.push(o.title);
|
|
63
|
+
return parts.join(" · ");
|
|
64
|
+
}
|