@canonical/pragma-cli 0.29.0 → 0.30.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 +67 -15
- package/dist/pragma +0 -0
- package/package.json +13 -13
- package/src/config/defaultConfig.test.ts +33 -0
- package/src/config/defaultConfig.ts +59 -0
- package/src/config/defaults.json +17 -0
- package/src/config/findProjectConfigPath.test.ts +53 -0
- package/src/config/findProjectConfigPath.ts +36 -0
- package/src/config/index.ts +17 -2
- package/src/config/mergeConfigFileUpdate.ts +58 -0
- package/src/config/parseConfigValues.ts +215 -0
- package/src/config/readConfig.test.ts +104 -13
- package/src/config/readConfig.ts +12 -153
- package/src/config/readConfigLayers.test.ts +107 -0
- package/src/config/readConfigLayers.ts +115 -0
- package/src/config/resolveGlobalConfigPath.ts +13 -0
- package/src/config/resolveWriteConfigPath.test.ts +53 -0
- package/src/config/resolveWriteConfigPath.ts +31 -0
- package/src/config/types.ts +76 -1
- package/src/config/writeConfig.ts +25 -55
- package/src/domains/block/commands/list.ts +5 -90
- package/src/domains/block/commands/lookup.ts +8 -167
- package/src/domains/block/mcp/specs.ts +16 -196
- package/src/domains/block/orchestration/resolveBlockLookup.ts +2 -1
- package/src/domains/block/stories.test.ts +28 -0
- package/src/domains/block/stories.ts +254 -0
- package/src/domains/config/commands/channel.test.ts +14 -3
- package/src/domains/config/commands/channel.ts +11 -7
- package/src/domains/config/commands/configScope.ts +46 -0
- package/src/domains/config/commands/framework.test.ts +18 -1
- package/src/domains/config/commands/framework.ts +13 -7
- package/src/domains/config/commands/show.ts +5 -45
- package/src/domains/config/commands/tier.test.ts +13 -2
- package/src/domains/config/commands/tier.ts +11 -7
- package/src/domains/config/commands/trace.test.ts +19 -2
- package/src/domains/config/commands/trace.ts +6 -3
- package/src/domains/config/formatters/channel.test.ts +20 -6
- package/src/domains/config/formatters/channel.ts +14 -11
- package/src/domains/config/formatters/framework.ts +14 -11
- package/src/domains/config/formatters/show.test.ts +27 -0
- package/src/domains/config/formatters/show.ts +27 -4
- package/src/domains/config/formatters/tier.test.ts +26 -10
- package/src/domains/config/formatters/tier.ts +19 -11
- package/src/domains/config/formatters/trace.ts +7 -7
- package/src/domains/config/mcp/specs.ts +33 -53
- package/src/domains/config/operations/show.test.ts +18 -0
- package/src/domains/config/operations/show.ts +7 -1
- package/src/domains/config/operations/types.ts +7 -0
- package/src/domains/config/stories.ts +42 -0
- package/src/domains/config/tasks/index.ts +1 -0
- package/src/domains/config/tasks/setChannel.ts +13 -28
- package/src/domains/config/tasks/setFramework.ts +11 -30
- package/src/domains/config/tasks/setTier.ts +10 -29
- package/src/domains/config/tasks/setTrace.ts +10 -28
- package/src/domains/config/tasks/writeConfigField.ts +41 -0
- package/src/domains/create/commands/component.ts +5 -5
- package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
- package/src/domains/doctor/operations/checks/checkMcpCommands.ts +130 -0
- package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
- package/src/domains/doctor/operations/checks/checkPackageRefs.ts +2 -14
- package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +1 -1
- package/src/domains/doctor/operations/checks/index.ts +1 -0
- package/src/domains/doctor/operations/checks.test.ts +158 -7
- package/src/domains/doctor/operations/runChecks.test.ts +15 -6
- package/src/domains/doctor/operations/runChecks.ts +2 -0
- package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
- package/src/domains/graph/helpers/resolveUri.ts +28 -21
- package/src/domains/graphql/commands/build.test.ts +5 -3
- package/src/domains/graphql/commands/build.ts +8 -16
- package/src/domains/graphql/commands/check.test.ts +5 -3
- package/src/domains/graphql/commands/check.ts +7 -13
- package/src/domains/graphql/commands/index.ts +1 -0
- package/src/domains/graphql/commands/serve.test.ts +40 -0
- package/src/domains/graphql/commands/serve.ts +131 -0
- package/src/domains/graphql/constants.ts +10 -0
- package/src/domains/graphql/helpers/gatherSources.test.ts +92 -0
- package/src/domains/graphql/helpers/gatherSources.ts +58 -0
- package/src/domains/graphql/helpers/index.ts +2 -0
- package/src/domains/graphql/helpers/routeGraphql.test.ts +43 -0
- package/src/domains/graphql/helpers/routeGraphql.ts +28 -0
- package/src/domains/graphql/index.ts +9 -6
- package/src/domains/graphql/operations/compileSchema.test.ts +21 -45
- package/src/domains/graphql/operations/compileSchema.ts +23 -25
- package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
- package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
- package/src/domains/graphql/operations/index.ts +5 -0
- package/src/domains/info/operations/collectInfo.test.ts +14 -3
- package/src/domains/info/operations/collectInfo.ts +12 -15
- package/src/domains/llm/capabilities.test.ts +4 -4
- package/src/domains/llm/data/toolCatalog.ts +6 -0
- package/src/domains/modifier/commands/list.ts +5 -38
- package/src/domains/modifier/commands/lookup.ts +8 -79
- package/src/domains/modifier/mcp/specs.ts +15 -94
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +2 -1
- package/src/domains/modifier/stories.test.ts +20 -0
- package/src/domains/modifier/stories.ts +77 -0
- package/src/domains/ontology/commands/list.ts +5 -58
- package/src/domains/ontology/commands/show.ts +6 -58
- package/src/domains/ontology/formatters/show.ts +7 -1
- package/src/domains/ontology/mcp/specs.ts +7 -84
- package/src/domains/ontology/stories.test.ts +36 -0
- package/src/domains/ontology/stories.ts +108 -0
- package/src/domains/refs/operations/updateRefs.ts +2 -37
- package/src/domains/setup/commands/skills.test.ts +6 -2
- package/src/domains/setup/commands/skills.ts +6 -2
- package/src/domains/setup/helpers/runSetupTask.test.ts +148 -150
- package/src/domains/setup/helpers/runSetupTask.ts +62 -70
- package/src/domains/setup/operations/setupMcp.test.ts +6 -1
- package/src/domains/shared/bootStore.ts +6 -3
- package/src/domains/shared/compactUri.test.ts +11 -0
- package/src/domains/shared/compactUri.ts +10 -5
- package/src/domains/shared/context.ts +2 -2
- package/src/domains/shared/contracts.ts +11 -0
- package/src/domains/shared/createInteractivePromptSession.test.ts +439 -0
- package/src/domains/shared/createInteractivePromptSession.ts +236 -0
- package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
- package/src/domains/shared/loaders/bundledLoader.ts +110 -12
- package/src/domains/shared/loaders/gitLoader.ts +2 -2
- package/src/domains/shared/loaders/index.ts +4 -1
- package/src/domains/shared/loaders/localLoader.ts +18 -4
- package/src/domains/shared/loaders/readPackageDir.ts +36 -1
- package/src/domains/shared/loaders/storyAssetsPlugin.test.ts +84 -0
- package/src/domains/shared/loaders/storyAssetsPlugin.ts +46 -0
- package/src/domains/shared/lookupMany.test.ts +120 -0
- package/src/domains/shared/lookupMany.ts +34 -2
- package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
- package/src/domains/shared/mergeAndParseRefs.ts +44 -0
- package/src/domains/shared/packages.ts +10 -17
- package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
- package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
- package/src/domains/shared/runtime.ts +4 -63
- package/src/domains/shared/semanticPackage.ts +17 -1
- package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
- package/src/domains/shared/stories/compileLookupCommand.ts +100 -0
- package/src/domains/shared/stories/compileLookupTool.test.ts +105 -0
- package/src/domains/shared/stories/compileLookupTool.ts +96 -0
- package/src/domains/shared/stories/compileReadCommand.test.ts +121 -0
- package/src/domains/shared/stories/compileReadCommand.ts +48 -0
- package/src/domains/shared/stories/compileReadTool.test.ts +64 -0
- package/src/domains/shared/stories/compileReadTool.ts +38 -0
- package/src/domains/shared/stories/condense.test.ts +18 -0
- package/src/domains/shared/stories/condense.ts +15 -0
- package/src/domains/shared/stories/index.ts +20 -0
- package/src/domains/shared/stories/normalizeNames.test.ts +20 -0
- package/src/domains/shared/stories/normalizeNames.ts +22 -0
- package/src/domains/shared/stories/pack/applyPackFilters.test.ts +102 -0
- package/src/domains/shared/stories/pack/applyPackFilters.ts +76 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +51 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.ts +80 -0
- package/src/domains/shared/stories/pack/collectPackStories.test.ts +108 -0
- package/src/domains/shared/stories/pack/collectPackStories.ts +76 -0
- package/src/domains/shared/stories/pack/compilePackCommands.ts +40 -0
- package/src/domains/shared/stories/pack/compilePackStories.test.ts +146 -0
- package/src/domains/shared/stories/pack/compilePackStories.ts +253 -0
- package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +43 -0
- package/src/domains/shared/stories/pack/index.ts +28 -0
- package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
- package/src/domains/shared/stories/pack/standardParity.test.ts +308 -0
- package/src/domains/shared/stories/pack/types.ts +104 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +240 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +408 -0
- package/src/domains/shared/stories/projectCliParameters.test.ts +59 -0
- package/src/domains/shared/stories/projectCliParameters.ts +57 -0
- package/src/domains/shared/stories/projectToolParams.test.ts +50 -0
- package/src/domains/shared/stories/projectToolParams.ts +32 -0
- package/src/domains/shared/stories/requirePragmaContext.test.ts +23 -0
- package/src/domains/shared/stories/requirePragmaContext.ts +23 -0
- package/src/domains/shared/stories/resolveLookupDetailed.test.ts +57 -0
- package/src/domains/shared/stories/resolveLookupDetailed.ts +27 -0
- package/src/domains/shared/stories/types.ts +171 -0
- package/src/domains/shared/suggestions/expandGlob.ts +1 -0
- package/src/domains/shared/suggestions/suggestNames.ts +43 -10
- package/src/domains/skill/commands/index.ts +3 -1
- package/src/domains/skill/commands/list.test.ts +6 -2
- package/src/domains/skill/commands/list.ts +5 -63
- package/src/domains/skill/commands/lookup.test.ts +118 -0
- package/src/domains/skill/commands/lookup.ts +14 -0
- package/src/domains/skill/formatters/index.ts +1 -0
- package/src/domains/skill/formatters/lookup.test.ts +46 -0
- package/src/domains/skill/formatters/lookup.ts +57 -0
- package/src/domains/skill/helpers/resolveSkillSources.ts +0 -1
- package/src/domains/skill/index.ts +7 -3
- package/src/domains/skill/mcp/specs.ts +10 -29
- package/src/domains/skill/operations/discover.test.ts +61 -30
- package/src/domains/skill/operations/discover.ts +28 -37
- package/src/domains/skill/operations/index.ts +2 -1
- package/src/domains/skill/operations/list.test.ts +15 -7
- package/src/domains/skill/operations/lookup.test.ts +91 -0
- package/src/domains/skill/operations/lookup.ts +70 -0
- package/src/domains/skill/stories.test.ts +43 -0
- package/src/domains/skill/stories.ts +103 -0
- package/src/domains/skill/types.ts +8 -0
- package/src/domains/standard/commands/list.ts +5 -84
- package/src/domains/standard/commands/lookup.ts +8 -93
- package/src/domains/standard/mcp/specs.ts +16 -171
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +2 -1
- package/src/domains/standard/stories.test.ts +24 -0
- package/src/domains/standard/stories.ts +151 -0
- package/src/domains/tier/commands/list.ts +5 -55
- package/src/domains/tier/mcp/specs.ts +5 -31
- package/src/domains/tier/stories.test.ts +22 -0
- package/src/domains/tier/stories.ts +52 -0
- package/src/domains/token/mcp/specs.ts +5 -1
- package/src/domains/token/orchestration/resolveTokenLookup.ts +2 -1
- package/src/domains/trace/tracePlugin.test.ts +1 -1
- package/src/mcp/registerResources.test.ts +382 -74
- package/src/mcp/registerResources.ts +5 -348
- package/src/mcp/resources/buildGraphIndex.ts +167 -0
- package/src/mcp/resources/buildResourceList.test.ts +97 -0
- package/src/mcp/resources/buildResourceList.ts +176 -0
- package/src/mcp/resources/classifyEntity.test.ts +40 -0
- package/src/mcp/resources/classifyEntity.ts +27 -0
- package/src/mcp/resources/constants.ts +105 -0
- package/src/mcp/resources/displayPredicates.ts +62 -0
- package/src/mcp/resources/pickFirstValue.test.ts +29 -0
- package/src/mcp/resources/pickFirstValue.ts +26 -0
- package/src/mcp/resources/pickPrimaryType.test.ts +41 -0
- package/src/mcp/resources/pickPrimaryType.ts +26 -0
- package/src/mcp/resources/rankUriCompletions.test.ts +52 -0
- package/src/mcp/resources/rankUriCompletions.ts +64 -0
- package/src/mcp/resources/readEntity.ts +169 -0
- package/src/mcp/resources/registerResources.ts +126 -0
- package/src/mcp/resources/types.ts +128 -0
- package/src/mcp/tools/index.ts +9 -0
- package/src/mcp/tools/registerTools.test.ts +65 -8
- package/src/mcp/types.ts +4 -0
- package/src/pipeline/collectCommands.ts +8 -1
- package/src/pipeline/runCli.ts +40 -6
- package/src/testing/createTestMcpClient.ts +4 -1
- package/src/testing/index.ts +10 -0
- package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
- package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
- package/src/testing/integration/executor-execution.test.ts +101 -0
- package/src/testing/integration/executor-golden.test.ts +145 -0
- package/src/testing/integration/mcp-surface.test.ts +1 -1
- package/src/testing/integration/parity.test.ts +17 -12
- package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
- package/src/testing/setupXdgIsolation.ts +15 -0
- package/src/testing/standardParityFixtures.ts +92 -0
- package/src/testing/storyFixtures.ts +63 -0
- package/src/pipeline/runInteractiveCommand.ts +0 -198
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill read stories — the single declaration of `skill list` and
|
|
3
|
+
* `skill lookup` for both surfaces.
|
|
4
|
+
*
|
|
5
|
+
* `skill lookup` serves the full SKILL.md content, making skills directly
|
|
6
|
+
* consumable by agents over MCP (previously only metadata was listed).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { PragmaError } from "#error";
|
|
10
|
+
import lookupMany from "../shared/lookupMany.js";
|
|
11
|
+
import {
|
|
12
|
+
type LookupStory,
|
|
13
|
+
type ReadStory,
|
|
14
|
+
requirePragmaContext,
|
|
15
|
+
} from "../shared/stories/index.js";
|
|
16
|
+
import { listFormatters, lookupFormatters } from "./formatters/index.js";
|
|
17
|
+
import type { SkillListInput } from "./formatters/types.js";
|
|
18
|
+
import {
|
|
19
|
+
discoverSkills,
|
|
20
|
+
listSkills,
|
|
21
|
+
lookupSkill,
|
|
22
|
+
type SkillListResult,
|
|
23
|
+
} from "./operations/index.js";
|
|
24
|
+
import type { SkillDetailed } from "./types.js";
|
|
25
|
+
|
|
26
|
+
/** The `skill list` / `skill_list` read story. */
|
|
27
|
+
export const skillListStory: ReadStory<SkillListResult, SkillListInput> = {
|
|
28
|
+
noun: "skill",
|
|
29
|
+
verb: "list",
|
|
30
|
+
description: "List available agent skills from design system packages",
|
|
31
|
+
toolDescription: "List available agent skills from design system packages.",
|
|
32
|
+
params: [
|
|
33
|
+
{
|
|
34
|
+
name: "detailed",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
description: "Show full metadata for each skill",
|
|
37
|
+
default: false,
|
|
38
|
+
surfaces: "cli",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
examples: [
|
|
42
|
+
"pragma skill list",
|
|
43
|
+
"pragma skill list --detailed",
|
|
44
|
+
"pragma skill list --llm",
|
|
45
|
+
"pragma skill list --format json",
|
|
46
|
+
],
|
|
47
|
+
resolve: (rt) => listSkills(rt.cwd),
|
|
48
|
+
toOutput: ({ skills, sources }, params) => ({
|
|
49
|
+
skills,
|
|
50
|
+
sources,
|
|
51
|
+
detailed: params.detailed === true,
|
|
52
|
+
}),
|
|
53
|
+
formatters: listFormatters,
|
|
54
|
+
toEnvelope: ({ skills, sources }) => ({
|
|
55
|
+
data: { skills, sources },
|
|
56
|
+
meta: { count: skills.length },
|
|
57
|
+
}),
|
|
58
|
+
emptyError: ({ skills, sources }) => {
|
|
59
|
+
if (skills.length > 0) return undefined;
|
|
60
|
+
const allUnavailable = sources.every((source) => !source.available);
|
|
61
|
+
return PragmaError.emptyResults("skill", {
|
|
62
|
+
recovery: {
|
|
63
|
+
message: allUnavailable
|
|
64
|
+
? "Install @canonical packages first"
|
|
65
|
+
: "No SKILL.md files found in source packages",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** The `skill lookup` / `skill_lookup` read story. */
|
|
72
|
+
export const skillLookupStory: LookupStory<SkillDetailed, SkillDetailed> = {
|
|
73
|
+
noun: "skill",
|
|
74
|
+
description: "Show full instructions for a skill by name",
|
|
75
|
+
toolDescription:
|
|
76
|
+
"Get full skill instructions (SKILL.md content) for one or more agent skills by name.",
|
|
77
|
+
namesDescription: "Skill names",
|
|
78
|
+
namesToolDescription: "Skill names to look up (e.g. ['design-auditor'])",
|
|
79
|
+
complete: async (partial, cmdCtx) => {
|
|
80
|
+
const ctx = requirePragmaContext(cmdCtx);
|
|
81
|
+
const skills = await discoverSkills(ctx.cwd);
|
|
82
|
+
return skills
|
|
83
|
+
.map((skill) => skill.name)
|
|
84
|
+
.filter((name) => name.toLowerCase().startsWith(partial.toLowerCase()));
|
|
85
|
+
},
|
|
86
|
+
examples: [
|
|
87
|
+
"pragma skill lookup design-auditor",
|
|
88
|
+
"pragma skill lookup design-auditor add-standard",
|
|
89
|
+
"pragma skill lookup design-auditor --llm",
|
|
90
|
+
],
|
|
91
|
+
resolve: (rt, names) =>
|
|
92
|
+
lookupMany(names, (query) => lookupSkill(rt.cwd, query)),
|
|
93
|
+
toFmtInput: (skill) => skill,
|
|
94
|
+
formatters: lookupFormatters,
|
|
95
|
+
emptyNamesError: () =>
|
|
96
|
+
PragmaError.invalidInput("names", "(empty)", {
|
|
97
|
+
recovery: {
|
|
98
|
+
message: "List available skills.",
|
|
99
|
+
cli: "pragma skill list",
|
|
100
|
+
mcp: { tool: "skill_list" },
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
@@ -23,3 +23,11 @@ export interface SkillSource {
|
|
|
23
23
|
readonly packageName: string;
|
|
24
24
|
readonly available: boolean;
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
/** A discovered skill enriched with its full SKILL.md content and companion files. */
|
|
28
|
+
export interface SkillDetailed extends DiscoveredSkill {
|
|
29
|
+
/** Full SKILL.md text, frontmatter included. */
|
|
30
|
+
readonly content: string;
|
|
31
|
+
/** Companion file names shipped next to SKILL.md (e.g. spec documents). */
|
|
32
|
+
readonly files: readonly string[];
|
|
33
|
+
}
|
|
@@ -1,90 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
* Wires the `pragma standard list` CLI command.
|
|
3
|
-
*
|
|
4
|
-
* Lists all code standards with optional category and search filters.
|
|
5
|
-
* Supports progressive disclosure via `--digest` (summary + first example)
|
|
6
|
-
* and `--detailed` (full dos/donts) flags.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
type CommandDefinition,
|
|
11
|
-
type CommandResult,
|
|
12
|
-
createOutputResult,
|
|
13
|
-
} from "@canonical/cli-core";
|
|
14
|
-
import { createListView } from "#tui";
|
|
1
|
+
import type { CommandDefinition } from "@canonical/cli-core";
|
|
15
2
|
import type { PragmaContext } from "../../shared/context.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import type { StandardListOutput } from "../formatters/types.js";
|
|
19
|
-
import { resolveStandardList } from "../orchestration/index.js";
|
|
20
|
-
import { standardConfig } from "../standardConfig.js";
|
|
3
|
+
import { compileReadCommand } from "../../shared/stories/index.js";
|
|
4
|
+
import { standardListStory } from "../stories.js";
|
|
21
5
|
|
|
6
|
+
/** Wire the `pragma standard list` CLI command from the standard list story. */
|
|
22
7
|
export default function buildListCommand(
|
|
23
8
|
ctx: PragmaContext,
|
|
24
9
|
): CommandDefinition {
|
|
25
|
-
return
|
|
26
|
-
path: ["standard", "list"],
|
|
27
|
-
description: "List all code standards",
|
|
28
|
-
parameters: [
|
|
29
|
-
{
|
|
30
|
-
name: "category",
|
|
31
|
-
description: "Filter by category",
|
|
32
|
-
type: "string",
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: "search",
|
|
36
|
-
description: "Search in name and description",
|
|
37
|
-
type: "string",
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: "digest",
|
|
41
|
-
description: "Show description and first example for each standard",
|
|
42
|
-
type: "boolean",
|
|
43
|
-
default: false,
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: "detailed",
|
|
47
|
-
description: "Show full dos/donts for each standard",
|
|
48
|
-
type: "boolean",
|
|
49
|
-
default: false,
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
meta: {
|
|
53
|
-
examples: [
|
|
54
|
-
"pragma standard list",
|
|
55
|
-
"pragma standard list --category react",
|
|
56
|
-
'pragma standard list --search "folder"',
|
|
57
|
-
"pragma standard list --digest",
|
|
58
|
-
"pragma standard list --detailed",
|
|
59
|
-
"pragma standard list --llm",
|
|
60
|
-
],
|
|
61
|
-
},
|
|
62
|
-
execute: async (
|
|
63
|
-
params: Record<string, unknown>,
|
|
64
|
-
): Promise<CommandResult> => {
|
|
65
|
-
const contract = await resolveStandardList(ctx, {
|
|
66
|
-
category: params.category as string | undefined,
|
|
67
|
-
search: params.search as string | undefined,
|
|
68
|
-
digest: params.digest === true,
|
|
69
|
-
detailed: params.detailed === true,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const output: StandardListOutput = {
|
|
73
|
-
items: contract.items,
|
|
74
|
-
details: contract.details,
|
|
75
|
-
disclosure: contract.disclosure,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
return createOutputResult(output, {
|
|
79
|
-
plain: selectFormatter(ctx, listFormatters),
|
|
80
|
-
ink: (data) =>
|
|
81
|
-
createListView({
|
|
82
|
-
heading: "Standards",
|
|
83
|
-
domain: "standard",
|
|
84
|
-
items: data.items,
|
|
85
|
-
columns: standardConfig.listColumns,
|
|
86
|
-
}),
|
|
87
|
-
});
|
|
88
|
-
},
|
|
89
|
-
};
|
|
10
|
+
return compileReadCommand(ctx, standardListStory);
|
|
90
11
|
}
|
|
@@ -1,99 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
* Wires the `pragma standard lookup <name-or-uri...>` CLI command.
|
|
3
|
-
*
|
|
4
|
-
* Retrieves detailed information for a single code standard, including
|
|
5
|
-
* optional dos/donts code blocks when `--detailed` is passed.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
type CommandDefinition,
|
|
10
|
-
type CommandResult,
|
|
11
|
-
createOutputResult,
|
|
12
|
-
} from "@canonical/cli-core";
|
|
13
|
-
import { createLookupView } from "#tui";
|
|
1
|
+
import type { CommandDefinition } from "@canonical/cli-core";
|
|
14
2
|
import type { PragmaContext } from "../../shared/context.js";
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
createInkLookupOptions,
|
|
19
|
-
lookupFormatters,
|
|
20
|
-
} from "../formatters/index.js";
|
|
21
|
-
import type { lookupStandard } from "../operations/index.js";
|
|
22
|
-
import { resolveStandardLookup } from "../orchestration/index.js";
|
|
23
|
-
|
|
24
|
-
interface StandardLookupOutput {
|
|
25
|
-
readonly result: LookupResult<Awaited<ReturnType<typeof lookupStandard>>>;
|
|
26
|
-
readonly detailed: boolean;
|
|
27
|
-
}
|
|
3
|
+
import { compileLookupCommand } from "../../shared/stories/index.js";
|
|
4
|
+
import { standardLookupStory } from "../stories.js";
|
|
28
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Wire the `pragma standard lookup <name-or-uri...>` CLI command from the
|
|
8
|
+
* standard lookup story.
|
|
9
|
+
*/
|
|
29
10
|
export default function buildLookupCommand(
|
|
30
11
|
ctx: PragmaContext,
|
|
31
12
|
): CommandDefinition {
|
|
32
|
-
return
|
|
33
|
-
path: ["standard", "lookup"],
|
|
34
|
-
description: "Look up detailed information for a standard by name or IRI",
|
|
35
|
-
parameters: [
|
|
36
|
-
{
|
|
37
|
-
name: "names",
|
|
38
|
-
description: "Standard names or IRIs",
|
|
39
|
-
type: "multiselect",
|
|
40
|
-
positional: true,
|
|
41
|
-
required: true,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "detailed",
|
|
45
|
-
description: "Include dos and donts with code blocks",
|
|
46
|
-
type: "boolean",
|
|
47
|
-
default: false,
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
meta: {
|
|
51
|
-
examples: [
|
|
52
|
-
"pragma standard lookup react/component/folder-structure",
|
|
53
|
-
"pragma standard lookup react/component/folder-structure react/component/props",
|
|
54
|
-
"pragma standard lookup react/component/folder-structure --detailed",
|
|
55
|
-
"pragma standard lookup react/component/folder-structure --llm",
|
|
56
|
-
"pragma standard lookup cs:react_props",
|
|
57
|
-
],
|
|
58
|
-
},
|
|
59
|
-
execute: async (
|
|
60
|
-
params: Record<string, unknown>,
|
|
61
|
-
): Promise<CommandResult> => {
|
|
62
|
-
const names = normalizeNames(params.names, params.name);
|
|
63
|
-
const detailed = (params.detailed as boolean) ?? false;
|
|
64
|
-
const contract = await resolveStandardLookup(ctx.store, names);
|
|
65
|
-
|
|
66
|
-
return createOutputResult<StandardLookupOutput>(
|
|
67
|
-
{ result: contract.result, detailed },
|
|
68
|
-
{
|
|
69
|
-
plain: ({ result, detailed: isDetailed }) =>
|
|
70
|
-
renderLookupResults({
|
|
71
|
-
ctx,
|
|
72
|
-
result,
|
|
73
|
-
formatters: lookupFormatters,
|
|
74
|
-
mapResult: (standard) => ({ standard, detailed: isDetailed }),
|
|
75
|
-
}),
|
|
76
|
-
ink: ({ result, detailed: isDetailed }) =>
|
|
77
|
-
createLookupView({
|
|
78
|
-
results: result.results,
|
|
79
|
-
errors: result.errors,
|
|
80
|
-
domain: "standard",
|
|
81
|
-
options: createInkLookupOptions(isDetailed),
|
|
82
|
-
}),
|
|
83
|
-
},
|
|
84
|
-
);
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function normalizeNames(names: unknown, legacyName?: unknown): string[] {
|
|
90
|
-
if (Array.isArray(names)) {
|
|
91
|
-
return names.filter(
|
|
92
|
-
(name): name is string => typeof name === "string" && name.length > 0,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
if (typeof legacyName === "string" && legacyName.length > 0) {
|
|
96
|
-
return [legacyName];
|
|
97
|
-
}
|
|
98
|
-
return [];
|
|
13
|
+
return compileLookupCommand(ctx, standardLookupStory);
|
|
99
14
|
}
|
|
@@ -1,172 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP tool specs for the standard domain
|
|
2
|
+
* MCP tool specs for the standard domain — standard_list, standard_lookup,
|
|
3
|
+
* standard_categories, standard_sample.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* The list and lookup tools are compiled from the standard read stories in
|
|
6
|
+
* `../stories.ts`; categories and sample are spec'd by hand. The adapter
|
|
7
|
+
* layer converts these into registered MCP tools via `registerFromSpec()`.
|
|
6
8
|
*/
|
|
7
9
|
|
|
10
|
+
import {
|
|
11
|
+
compileLookupTool,
|
|
12
|
+
compileReadTool,
|
|
13
|
+
condense,
|
|
14
|
+
} from "../../shared/stories/index.js";
|
|
8
15
|
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
9
16
|
import {
|
|
10
|
-
type StandardListOutput,
|
|
11
17
|
categoriesFormatters as standardCatFmt,
|
|
12
|
-
listFormatters as standardListFmt,
|
|
13
|
-
lookupFormatters as standardLookupFmt,
|
|
14
18
|
sampleFormatters as standardSampleFmt,
|
|
15
19
|
} from "../formatters/index.js";
|
|
16
20
|
import { listCategories, sampleStandards } from "../operations/index.js";
|
|
17
|
-
import {
|
|
18
|
-
resolveStandardList,
|
|
19
|
-
resolveStandardLookup,
|
|
20
|
-
} from "../orchestration/index.js";
|
|
21
|
+
import { standardListStory, standardLookupStory } from "../stories.js";
|
|
21
22
|
|
|
22
23
|
const specs: readonly ToolSpec[] = [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
description:
|
|
26
|
-
"List code standards. Optionally filter by category or search term. Use digest/detailed for progressive disclosure.",
|
|
27
|
-
params: {
|
|
28
|
-
category: {
|
|
29
|
-
type: "string",
|
|
30
|
-
description: "Filter by category name",
|
|
31
|
-
optional: true,
|
|
32
|
-
},
|
|
33
|
-
search: {
|
|
34
|
-
type: "string",
|
|
35
|
-
description: "Search in name and description",
|
|
36
|
-
optional: true,
|
|
37
|
-
},
|
|
38
|
-
digest: {
|
|
39
|
-
type: "boolean",
|
|
40
|
-
description: "Show description and first example for each standard",
|
|
41
|
-
optional: true,
|
|
42
|
-
},
|
|
43
|
-
detailed: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
description: "Show full dos/donts for each standard",
|
|
46
|
-
optional: true,
|
|
47
|
-
},
|
|
48
|
-
condensed: {
|
|
49
|
-
type: "boolean",
|
|
50
|
-
description: "Token-optimized output",
|
|
51
|
-
optional: true,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
readOnly: true,
|
|
55
|
-
async execute(rt, { category, search, digest, detailed, condensed }) {
|
|
56
|
-
const resolution = await resolveStandardList(rt, {
|
|
57
|
-
category: category as string | undefined,
|
|
58
|
-
search: search as string | undefined,
|
|
59
|
-
digest: digest === true,
|
|
60
|
-
detailed: detailed === true,
|
|
61
|
-
});
|
|
62
|
-
const output: StandardListOutput = {
|
|
63
|
-
items: resolution.items,
|
|
64
|
-
details: resolution.details,
|
|
65
|
-
disclosure: resolution.disclosure,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
if (condensed) {
|
|
69
|
-
const text = standardListFmt.llm(output);
|
|
70
|
-
return {
|
|
71
|
-
condensed: true,
|
|
72
|
-
text,
|
|
73
|
-
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (resolution.disclosure.level === "summary") {
|
|
78
|
-
return {
|
|
79
|
-
data: resolution.items,
|
|
80
|
-
meta: { count: resolution.items.length },
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
data: JSON.parse(standardListFmt.json(output)),
|
|
86
|
-
meta: {
|
|
87
|
-
count: resolution.items.length,
|
|
88
|
-
disclosure: resolution.disclosure.level,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
{
|
|
95
|
-
name: "standard_lookup",
|
|
96
|
-
description:
|
|
97
|
-
"Get detailed information about one or more code standards including dos and donts with code examples.",
|
|
98
|
-
params: {
|
|
99
|
-
names: {
|
|
100
|
-
type: "string[]",
|
|
101
|
-
description: "Standard names or IRIs to look up",
|
|
102
|
-
optional: false,
|
|
103
|
-
},
|
|
104
|
-
detailed: {
|
|
105
|
-
type: "boolean",
|
|
106
|
-
description:
|
|
107
|
-
"Return full details with dos/donts (default: true for MCP)",
|
|
108
|
-
optional: true,
|
|
109
|
-
},
|
|
110
|
-
condensed: {
|
|
111
|
-
type: "boolean",
|
|
112
|
-
description: "Token-optimized output",
|
|
113
|
-
optional: true,
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
readOnly: true,
|
|
117
|
-
async execute(rt, { names, detailed, condensed }) {
|
|
118
|
-
const showDetailed = (detailed as boolean | undefined) ?? true;
|
|
119
|
-
const contract = await resolveStandardLookup(rt.store, names as string[]);
|
|
120
|
-
const result = contract.result;
|
|
121
|
-
|
|
122
|
-
if (condensed) {
|
|
123
|
-
const textParts = result.results.map((standard) =>
|
|
124
|
-
standardLookupFmt.llm({
|
|
125
|
-
standard,
|
|
126
|
-
detailed: showDetailed,
|
|
127
|
-
}),
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
if (result.errors.length > 0) {
|
|
131
|
-
textParts.push(
|
|
132
|
-
[
|
|
133
|
-
"### Errors",
|
|
134
|
-
...result.errors.map(
|
|
135
|
-
(error) => `- ${error.query}: ${error.message}`,
|
|
136
|
-
),
|
|
137
|
-
].join("\n"),
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const text = textParts.join("\n\n");
|
|
142
|
-
return {
|
|
143
|
-
condensed: true,
|
|
144
|
-
text,
|
|
145
|
-
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (!showDetailed) {
|
|
150
|
-
return {
|
|
151
|
-
data: {
|
|
152
|
-
results: result.results.map(
|
|
153
|
-
({ uri, name, category, description }) => ({
|
|
154
|
-
uri,
|
|
155
|
-
name,
|
|
156
|
-
category,
|
|
157
|
-
description,
|
|
158
|
-
}),
|
|
159
|
-
),
|
|
160
|
-
errors: result.errors,
|
|
161
|
-
},
|
|
162
|
-
meta: { count: result.results.length },
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return { data: result, meta: { count: result.results.length } };
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
|
|
24
|
+
compileReadTool(standardListStory),
|
|
25
|
+
compileLookupTool(standardLookupStory),
|
|
170
26
|
{
|
|
171
27
|
name: "standard_categories",
|
|
172
28
|
description: "List all code standard categories.",
|
|
@@ -182,18 +38,12 @@ const specs: readonly ToolSpec[] = [
|
|
|
182
38
|
const result = await listCategories(rt.store);
|
|
183
39
|
|
|
184
40
|
if (condensed) {
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
condensed: true,
|
|
188
|
-
text,
|
|
189
|
-
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
190
|
-
};
|
|
41
|
+
return condense(standardCatFmt.llm(result));
|
|
191
42
|
}
|
|
192
43
|
|
|
193
44
|
return { data: result, meta: { count: result.length } };
|
|
194
45
|
},
|
|
195
46
|
},
|
|
196
|
-
|
|
197
47
|
{
|
|
198
48
|
name: "standard_sample",
|
|
199
49
|
description:
|
|
@@ -221,12 +71,7 @@ const specs: readonly ToolSpec[] = [
|
|
|
221
71
|
];
|
|
222
72
|
|
|
223
73
|
if (condensed) {
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
condensed: true,
|
|
227
|
-
text,
|
|
228
|
-
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
229
|
-
};
|
|
74
|
+
return condense(standardSampleFmt.llm({ ...result, nextSteps }));
|
|
230
75
|
}
|
|
231
76
|
|
|
232
77
|
return {
|
|
@@ -239,6 +84,6 @@ const specs: readonly ToolSpec[] = [
|
|
|
239
84
|
};
|
|
240
85
|
},
|
|
241
86
|
},
|
|
242
|
-
];
|
|
87
|
+
] as const;
|
|
243
88
|
|
|
244
89
|
export default specs;
|
|
@@ -18,11 +18,12 @@ export default async function resolveStandardLookup(
|
|
|
18
18
|
const lookupResult: LookupResult<StandardDetailed> =
|
|
19
19
|
names.length > 0
|
|
20
20
|
? await lookupMany(names, (query) => lookupStandard(store, query))
|
|
21
|
-
: { results: [], errors: [] };
|
|
21
|
+
: { results: [], errors: [], meta: { internalErrorCount: 0 } };
|
|
22
22
|
|
|
23
23
|
const result: LookupResult<StandardDetailed> = {
|
|
24
24
|
results: lookupResult.results,
|
|
25
25
|
errors: [...lookupResult.errors, ...globErrors],
|
|
26
|
+
meta: lookupResult.meta ?? { internalErrorCount: 0 },
|
|
26
27
|
};
|
|
27
28
|
|
|
28
29
|
return {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { standardListStory, standardLookupStory } from "./stories.js";
|
|
3
|
+
|
|
4
|
+
describe("standardListStory", () => {
|
|
5
|
+
it("renders the ink list view", () => {
|
|
6
|
+
const view = standardListStory.renderInk?.({
|
|
7
|
+
items: [],
|
|
8
|
+
details: undefined,
|
|
9
|
+
disclosure: { level: "summary" },
|
|
10
|
+
});
|
|
11
|
+
expect(typeof view).toBe("string");
|
|
12
|
+
expect(view).toContain("Standards");
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("standardLookupStory", () => {
|
|
17
|
+
it("renders the ink lookup view", () => {
|
|
18
|
+
const view = standardLookupStory.renderInk?.(
|
|
19
|
+
{ results: [], errors: [] },
|
|
20
|
+
{ surface: "cli", detailed: false, params: {} },
|
|
21
|
+
);
|
|
22
|
+
expect(typeof view).toBe("string");
|
|
23
|
+
});
|
|
24
|
+
});
|