@canonical/pragma-cli 0.18.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 +377 -0
- package/package.json +78 -0
- package/src/bin.test.ts +52 -0
- package/src/bin.ts +19 -0
- package/src/compile-validation.runner.ts +137 -0
- package/src/compile-validation.ts +192 -0
- package/src/completions/computeSocketPath.test.ts +26 -0
- package/src/completions/computeSocketPath.ts +16 -0
- package/src/completions/constants.ts +18 -0
- package/src/completions/handleQuery.test.ts +93 -0
- package/src/completions/handleQuery.ts +30 -0
- package/src/completions/index.ts +14 -0
- package/src/completions/queryCompletions.test.ts +100 -0
- package/src/completions/queryCompletions.ts +61 -0
- package/src/completions/querySocket.test.ts +70 -0
- package/src/completions/querySocket.ts +44 -0
- package/src/completions/startCompletionsServer.test.ts +74 -0
- package/src/completions/startCompletionsServer.ts +75 -0
- package/src/completions/startCompletionsServer.unit.test.ts +131 -0
- package/src/completions/waitForSocket.test.ts +27 -0
- package/src/completions/waitForSocket.ts +27 -0
- package/src/config/configExists.ts +14 -0
- package/src/config/index.ts +6 -0
- package/src/config/readConfig.test.ts +152 -0
- package/src/config/readConfig.ts +64 -0
- package/src/config/resolveConfigPath.test.ts +20 -0
- package/src/config/resolveConfigPath.ts +11 -0
- package/src/config/types.ts +26 -0
- package/src/config/writeConfig.ts +49 -0
- package/src/constants.ts +78 -0
- package/src/domains/block/blockConfig.ts +53 -0
- package/src/domains/block/commands/index.ts +4 -0
- package/src/domains/block/commands/list.test.ts +111 -0
- package/src/domains/block/commands/list.ts +69 -0
- package/src/domains/block/commands/lookup.test.ts +187 -0
- package/src/domains/block/commands/lookup.ts +199 -0
- package/src/domains/block/formatters/index.ts +4 -0
- package/src/domains/block/formatters/list.test.ts +107 -0
- package/src/domains/block/formatters/list.ts +64 -0
- package/src/domains/block/formatters/lookup.test.ts +317 -0
- package/src/domains/block/formatters/lookup.ts +354 -0
- package/src/domains/block/formatters/types.ts +16 -0
- package/src/domains/block/helpers/index.ts +4 -0
- package/src/domains/block/helpers/resolveAspects.test.ts +64 -0
- package/src/domains/block/helpers/resolveAspects.ts +35 -0
- package/src/domains/block/index.ts +25 -0
- package/src/domains/block/mcp/index.ts +2 -0
- package/src/domains/block/mcp/specs.ts +199 -0
- package/src/domains/block/operations/index.ts +4 -0
- package/src/domains/block/operations/list.test.ts +80 -0
- package/src/domains/block/operations/list.ts +72 -0
- package/src/domains/block/operations/lookup.test.ts +108 -0
- package/src/domains/block/operations/lookup.ts +359 -0
- package/src/domains/block/orchestration/blockEmptyError.ts +19 -0
- package/src/domains/block/orchestration/buildBlockFilters.ts +12 -0
- package/src/domains/block/orchestration/enrichBlocks.ts +37 -0
- package/src/domains/block/orchestration/index.ts +5 -0
- package/src/domains/block/orchestration/resolveBlockList.ts +39 -0
- package/src/domains/block/orchestration/resolveBlockLookup.ts +21 -0
- package/src/domains/block/types.ts +30 -0
- package/src/domains/config/commands/channel.test.ts +101 -0
- package/src/domains/config/commands/channel.ts +80 -0
- package/src/domains/config/commands/index.ts +4 -0
- package/src/domains/config/commands/show.test.ts +61 -0
- package/src/domains/config/commands/show.ts +51 -0
- package/src/domains/config/commands/tier.test.ts +84 -0
- package/src/domains/config/commands/tier.ts +78 -0
- package/src/domains/config/formatters/channel.test.ts +56 -0
- package/src/domains/config/formatters/channel.ts +34 -0
- package/src/domains/config/formatters/index.ts +4 -0
- package/src/domains/config/formatters/show.test.ts +126 -0
- package/src/domains/config/formatters/show.ts +66 -0
- package/src/domains/config/formatters/tier.test.ts +70 -0
- package/src/domains/config/formatters/tier.ts +40 -0
- package/src/domains/config/index.ts +23 -0
- package/src/domains/config/mcp/index.ts +2 -0
- package/src/domains/config/mcp/specs.ts +108 -0
- package/src/domains/config/operations/index.ts +5 -0
- package/src/domains/config/operations/show.test.ts +60 -0
- package/src/domains/config/operations/show.ts +42 -0
- package/src/domains/config/operations/types.ts +13 -0
- package/src/domains/config/operations/validateChannel.test.ts +36 -0
- package/src/domains/config/operations/validateChannel.ts +24 -0
- package/src/domains/config/operations/validateTier.test.ts +56 -0
- package/src/domains/config/operations/validateTier.ts +35 -0
- package/src/domains/create/commands/component.test.ts +166 -0
- package/src/domains/create/commands/component.ts +129 -0
- package/src/domains/create/commands/index.ts +3 -0
- package/src/domains/create/commands/package.test.ts +35 -0
- package/src/domains/create/commands/package.ts +21 -0
- package/src/domains/create/index.ts +15 -0
- package/src/domains/create/mcp/index.ts +2 -0
- package/src/domains/create/mcp/specs.ts +174 -0
- package/src/domains/doctor/commands/doctor.test.ts +75 -0
- package/src/domains/doctor/commands/doctor.ts +43 -0
- package/src/domains/doctor/commands/index.ts +2 -0
- package/src/domains/doctor/formatters/doctor.test.ts +117 -0
- package/src/domains/doctor/formatters/doctor.ts +84 -0
- package/src/domains/doctor/formatters/index.ts +2 -0
- package/src/domains/doctor/index.ts +9 -0
- package/src/domains/doctor/mcp/index.ts +2 -0
- package/src/domains/doctor/mcp/specs.ts +88 -0
- package/src/domains/doctor/operations/checks/checkConfigFile.ts +28 -0
- package/src/domains/doctor/operations/checks/checkKeStore.ts +38 -0
- package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +65 -0
- package/src/domains/doctor/operations/checks/checkNodeVersion.ts +25 -0
- package/src/domains/doctor/operations/checks/checkPragmaVersion.ts +20 -0
- package/src/domains/doctor/operations/checks/checkShellCompletions.ts +42 -0
- package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +64 -0
- package/src/domains/doctor/operations/checks/index.ts +8 -0
- package/src/domains/doctor/operations/checks.test.ts +151 -0
- package/src/domains/doctor/operations/index.ts +3 -0
- package/src/domains/doctor/operations/runChecks.test.ts +89 -0
- package/src/domains/doctor/operations/runChecks.ts +38 -0
- package/src/domains/doctor/operations/types.ts +20 -0
- package/src/domains/graph/commands/index.ts +4 -0
- package/src/domains/graph/commands/inspect.test.ts +94 -0
- package/src/domains/graph/commands/inspect.ts +63 -0
- package/src/domains/graph/commands/query.test.ts +92 -0
- package/src/domains/graph/commands/query.ts +60 -0
- package/src/domains/graph/formatters/index.ts +4 -0
- package/src/domains/graph/formatters/inspect.ts +45 -0
- package/src/domains/graph/formatters/query.ts +37 -0
- package/src/domains/graph/helpers/index.ts +3 -0
- package/src/domains/graph/helpers/resolveUri.ts +70 -0
- package/src/domains/graph/index.ts +22 -0
- package/src/domains/graph/mcp/index.ts +2 -0
- package/src/domains/graph/mcp/specs.ts +82 -0
- package/src/domains/graph/operations/executeQuery.test.ts +68 -0
- package/src/domains/graph/operations/executeQuery.ts +32 -0
- package/src/domains/graph/operations/index.ts +4 -0
- package/src/domains/graph/operations/inspectUri.test.ts +101 -0
- package/src/domains/graph/operations/inspectUri.ts +61 -0
- package/src/domains/info/commands/index.ts +4 -0
- package/src/domains/info/commands/info.test.ts +88 -0
- package/src/domains/info/commands/info.ts +47 -0
- package/src/domains/info/commands/upgrade.test.ts +183 -0
- package/src/domains/info/commands/upgrade.ts +150 -0
- package/src/domains/info/constants.test.ts +22 -0
- package/src/domains/info/constants.ts +15 -0
- package/src/domains/info/formatters/index.ts +8 -0
- package/src/domains/info/formatters/info.test.ts +173 -0
- package/src/domains/info/formatters/info.ts +116 -0
- package/src/domains/info/formatters/upgrade.test.ts +133 -0
- package/src/domains/info/formatters/upgrade.ts +68 -0
- package/src/domains/info/index.ts +7 -0
- package/src/domains/info/operations/checkRegistryVersion.test.ts +124 -0
- package/src/domains/info/operations/checkRegistryVersion.ts +45 -0
- package/src/domains/info/operations/collectInfo.test.ts +111 -0
- package/src/domains/info/operations/collectInfo.ts +68 -0
- package/src/domains/info/operations/collectStoreSummary.test.ts +61 -0
- package/src/domains/info/operations/collectStoreSummary.ts +42 -0
- package/src/domains/info/operations/index.ts +5 -0
- package/src/domains/info/types.test-d.ts +35 -0
- package/src/domains/info/types.ts +46 -0
- package/src/domains/llm/commands/index.ts +3 -0
- package/src/domains/llm/commands/llm.ts +37 -0
- package/src/domains/llm/data/commandReference.ts +25 -0
- package/src/domains/llm/data/decisionTrees.ts +46 -0
- package/src/domains/llm/data/index.ts +4 -0
- package/src/domains/llm/formatters/index.ts +3 -0
- package/src/domains/llm/formatters/orientation.ts +53 -0
- package/src/domains/llm/index.ts +8 -0
- package/src/domains/llm/llmCommand.test.ts +93 -0
- package/src/domains/llm/mcp/index.ts +2 -0
- package/src/domains/llm/mcp/specs.ts +87 -0
- package/src/domains/llm/operations/collectContext.ts +47 -0
- package/src/domains/llm/operations/index.ts +3 -0
- package/src/domains/llm/types.ts +32 -0
- package/src/domains/modifier/commands/index.ts +4 -0
- package/src/domains/modifier/commands/list.test.ts +57 -0
- package/src/domains/modifier/commands/list.ts +33 -0
- package/src/domains/modifier/commands/lookup.test.ts +91 -0
- package/src/domains/modifier/commands/lookup.ts +105 -0
- package/src/domains/modifier/formatters/index.ts +4 -0
- package/src/domains/modifier/formatters/list.test.ts +38 -0
- package/src/domains/modifier/formatters/list.ts +35 -0
- package/src/domains/modifier/formatters/lookup.test.ts +33 -0
- package/src/domains/modifier/formatters/lookup.ts +38 -0
- package/src/domains/modifier/index.ts +22 -0
- package/src/domains/modifier/mcp/index.ts +2 -0
- package/src/domains/modifier/mcp/specs.ts +97 -0
- package/src/domains/modifier/operations/index.ts +4 -0
- package/src/domains/modifier/operations/list.test.ts +39 -0
- package/src/domains/modifier/operations/list.ts +41 -0
- package/src/domains/modifier/operations/lookup.test.ts +37 -0
- package/src/domains/modifier/operations/lookup.ts +57 -0
- package/src/domains/modifier/orchestration/index.ts +3 -0
- package/src/domains/modifier/orchestration/modifierEmptyError.ts +10 -0
- package/src/domains/modifier/orchestration/resolveModifierList.ts +16 -0
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +20 -0
- package/src/domains/modifier/types.ts +5 -0
- package/src/domains/ontology/commands/index.ts +4 -0
- package/src/domains/ontology/commands/list.test.ts +82 -0
- package/src/domains/ontology/commands/list.ts +46 -0
- package/src/domains/ontology/commands/show.test.ts +103 -0
- package/src/domains/ontology/commands/show.ts +66 -0
- package/src/domains/ontology/formatters/index.ts +4 -0
- package/src/domains/ontology/formatters/list.ts +37 -0
- package/src/domains/ontology/formatters/show.ts +74 -0
- package/src/domains/ontology/helpers/findNamespace.ts +23 -0
- package/src/domains/ontology/helpers/index.ts +7 -0
- package/src/domains/ontology/helpers/queryClasses.ts +50 -0
- package/src/domains/ontology/helpers/queryProperties.ts +57 -0
- package/src/domains/ontology/helpers/resolvePrefix.ts +45 -0
- package/src/domains/ontology/index.ts +26 -0
- package/src/domains/ontology/mcp/index.ts +2 -0
- package/src/domains/ontology/mcp/specs.ts +93 -0
- package/src/domains/ontology/operations/index.ts +5 -0
- package/src/domains/ontology/operations/listOntologies.test.ts +45 -0
- package/src/domains/ontology/operations/listOntologies.ts +101 -0
- package/src/domains/ontology/operations/showOntology.test.ts +65 -0
- package/src/domains/ontology/operations/showOntology.ts +41 -0
- package/src/domains/ontology/operations/showOntologyRaw.test.ts +39 -0
- package/src/domains/ontology/operations/showOntologyRaw.ts +50 -0
- package/src/domains/setup/commands/all.ts +58 -0
- package/src/domains/setup/commands/completions.ts +85 -0
- package/src/domains/setup/commands/entrypoints.test.ts +170 -0
- package/src/domains/setup/commands/index.ts +6 -0
- package/src/domains/setup/commands/lsp.ts +49 -0
- package/src/domains/setup/commands/mcp.ts +119 -0
- package/src/domains/setup/commands/skills.test.ts +64 -0
- package/src/domains/setup/commands/skills.ts +106 -0
- package/src/domains/setup/formatters/index.ts +2 -0
- package/src/domains/setup/formatters/skills.test.ts +103 -0
- package/src/domains/setup/formatters/skills.ts +112 -0
- package/src/domains/setup/formatters/types.ts +7 -0
- package/src/domains/setup/helpers/completionScripts.test.ts +58 -0
- package/src/domains/setup/helpers/completionScripts.ts +92 -0
- package/src/domains/setup/helpers/constants.ts +2 -0
- package/src/domains/setup/helpers/detectShell.test.ts +48 -0
- package/src/domains/setup/helpers/detectShell.ts +20 -0
- package/src/domains/setup/helpers/index.ts +12 -0
- package/src/domains/setup/helpers/runSetupTask.test.ts +279 -0
- package/src/domains/setup/helpers/runSetupTask.ts +229 -0
- package/src/domains/setup/index.ts +33 -0
- package/src/domains/setup/operations/index.ts +6 -0
- package/src/domains/setup/operations/setupAll.test.ts +48 -0
- package/src/domains/setup/operations/setupAll.ts +41 -0
- package/src/domains/setup/operations/setupCompletions.test.ts +94 -0
- package/src/domains/setup/operations/setupCompletions.ts +54 -0
- package/src/domains/setup/operations/setupLsp.test.ts +29 -0
- package/src/domains/setup/operations/setupLsp.ts +17 -0
- package/src/domains/setup/operations/setupMcp.test.ts +115 -0
- package/src/domains/setup/operations/setupMcp.ts +108 -0
- package/src/domains/setup/operations/setupSkills.test.ts +191 -0
- package/src/domains/setup/operations/setupSkills.ts +160 -0
- package/src/domains/setup/types.ts +18 -0
- package/src/domains/shared/ToolSpec.ts +49 -0
- package/src/domains/shared/bootStore.ts +77 -0
- package/src/domains/shared/buildQuery.ts +18 -0
- package/src/domains/shared/compactUri.test.ts +21 -0
- package/src/domains/shared/compactUri.ts +16 -0
- package/src/domains/shared/context.ts +15 -0
- package/src/domains/shared/contracts.ts +113 -0
- package/src/domains/shared/extractLocalName.test.ts +21 -0
- package/src/domains/shared/extractLocalName.ts +14 -0
- package/src/domains/shared/filters/buildChannelFilter.test.ts +52 -0
- package/src/domains/shared/filters/buildChannelFilter.ts +41 -0
- package/src/domains/shared/filters/buildFilterConfig.ts +16 -0
- package/src/domains/shared/filters/buildFilters.test.ts +33 -0
- package/src/domains/shared/filters/buildFilters.ts +30 -0
- package/src/domains/shared/filters/buildTierFilter.test.ts +78 -0
- package/src/domains/shared/filters/buildTierFilter.ts +69 -0
- package/src/domains/shared/filters/describeFilters.ts +14 -0
- package/src/domains/shared/filters/index.ts +10 -0
- package/src/domains/shared/formatters.ts +35 -0
- package/src/domains/shared/lookupMany.ts +45 -0
- package/src/domains/shared/namespaces.ts +18 -0
- package/src/domains/shared/packages.ts +76 -0
- package/src/domains/shared/prefixes.ts +37 -0
- package/src/domains/shared/runtime.ts +62 -0
- package/src/domains/shared/types.test-d.ts +127 -0
- package/src/domains/shared/types.ts +348 -0
- package/src/domains/skill/commands/index.ts +2 -0
- package/src/domains/skill/commands/list.test.ts +111 -0
- package/src/domains/skill/commands/list.ts +69 -0
- package/src/domains/skill/formatters/index.ts +2 -0
- package/src/domains/skill/formatters/list.test.ts +140 -0
- package/src/domains/skill/formatters/list.ts +119 -0
- package/src/domains/skill/formatters/types.ts +8 -0
- package/src/domains/skill/helpers/index.ts +6 -0
- package/src/domains/skill/helpers/parseFrontmatter.test.ts +122 -0
- package/src/domains/skill/helpers/parseFrontmatter.ts +112 -0
- package/src/domains/skill/helpers/resolveSkillSources.ts +34 -0
- package/src/domains/skill/index.ts +19 -0
- package/src/domains/skill/mcp/index.ts +2 -0
- package/src/domains/skill/mcp/specs.ts +38 -0
- package/src/domains/skill/operations/discover.test.ts +145 -0
- package/src/domains/skill/operations/discover.ts +68 -0
- package/src/domains/skill/operations/index.ts +4 -0
- package/src/domains/skill/operations/list.test.ts +68 -0
- package/src/domains/skill/operations/list.ts +47 -0
- package/src/domains/skill/types.ts +25 -0
- package/src/domains/standard/commands/categories.test.ts +70 -0
- package/src/domains/standard/commands/categories.ts +48 -0
- package/src/domains/standard/commands/index.ts +5 -0
- package/src/domains/standard/commands/list.test.ts +105 -0
- package/src/domains/standard/commands/list.ts +81 -0
- package/src/domains/standard/commands/lookup.test.ts +135 -0
- package/src/domains/standard/commands/lookup.ts +127 -0
- package/src/domains/standard/formatters/categories.test.ts +44 -0
- package/src/domains/standard/formatters/categories.ts +38 -0
- package/src/domains/standard/formatters/index.ts +6 -0
- package/src/domains/standard/formatters/list.test.ts +166 -0
- package/src/domains/standard/formatters/list.ts +156 -0
- package/src/domains/standard/formatters/lookup.test.ts +95 -0
- package/src/domains/standard/formatters/lookup.ts +86 -0
- package/src/domains/standard/formatters/types.ts +31 -0
- package/src/domains/standard/index.ts +32 -0
- package/src/domains/standard/mcp/index.ts +2 -0
- package/src/domains/standard/mcp/specs.ts +197 -0
- package/src/domains/standard/operations/categories.test.ts +61 -0
- package/src/domains/standard/operations/categories.ts +38 -0
- package/src/domains/standard/operations/index.ts +5 -0
- package/src/domains/standard/operations/list.test.ts +75 -0
- package/src/domains/standard/operations/list.ts +64 -0
- package/src/domains/standard/operations/lookup.test.ts +58 -0
- package/src/domains/standard/operations/lookup.ts +142 -0
- package/src/domains/standard/orchestration/buildStandardFilters.ts +11 -0
- package/src/domains/standard/orchestration/index.ts +4 -0
- package/src/domains/standard/orchestration/resolveStandardList.ts +42 -0
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +20 -0
- package/src/domains/standard/orchestration/standardEmptyError.ts +19 -0
- package/src/domains/standard/types.ts +15 -0
- package/src/domains/tier/commands/index.ts +3 -0
- package/src/domains/tier/commands/list.test.ts +67 -0
- package/src/domains/tier/commands/list.ts +43 -0
- package/src/domains/tier/formatters/index.ts +3 -0
- package/src/domains/tier/formatters/list.test.ts +33 -0
- package/src/domains/tier/formatters/list.ts +40 -0
- package/src/domains/tier/index.ts +17 -0
- package/src/domains/tier/mcp/index.ts +2 -0
- package/src/domains/tier/mcp/specs.ts +38 -0
- package/src/domains/tier/operations/index.ts +3 -0
- package/src/domains/tier/operations/list.test.ts +32 -0
- package/src/domains/tier/operations/list.ts +33 -0
- package/src/domains/token/commands/add-config.test.ts +68 -0
- package/src/domains/token/commands/add-config.ts +62 -0
- package/src/domains/token/commands/index.ts +5 -0
- package/src/domains/token/commands/list.test.ts +82 -0
- package/src/domains/token/commands/list.ts +45 -0
- package/src/domains/token/commands/lookup.test.ts +125 -0
- package/src/domains/token/commands/lookup.ts +121 -0
- package/src/domains/token/formatters/index.ts +4 -0
- package/src/domains/token/formatters/list.test.ts +37 -0
- package/src/domains/token/formatters/list.ts +37 -0
- package/src/domains/token/formatters/lookup.test.ts +61 -0
- package/src/domains/token/formatters/lookup.ts +72 -0
- package/src/domains/token/index.ts +32 -0
- package/src/domains/token/mcp/index.ts +2 -0
- package/src/domains/token/mcp/specs.ts +145 -0
- package/src/domains/token/operations/add-config.test.ts +68 -0
- package/src/domains/token/operations/add-config.ts +61 -0
- package/src/domains/token/operations/index.ts +7 -0
- package/src/domains/token/operations/list.test.ts +50 -0
- package/src/domains/token/operations/list.ts +52 -0
- package/src/domains/token/operations/lookup.test.ts +42 -0
- package/src/domains/token/operations/lookup.ts +66 -0
- package/src/domains/token/orchestration/index.ts +3 -0
- package/src/domains/token/orchestration/resolveTokenList.ts +17 -0
- package/src/domains/token/orchestration/resolveTokenLookup.ts +20 -0
- package/src/domains/token/orchestration/tokenEmptyError.ts +17 -0
- package/src/domains/token/types.ts +6 -0
- package/src/error/PragmaError.test.ts +121 -0
- package/src/error/PragmaError.ts +164 -0
- package/src/error/constants.ts +12 -0
- package/src/error/index.ts +4 -0
- package/src/error/types.ts +41 -0
- package/src/index.ts +141 -0
- package/src/mcp/createMcpServer.test.ts +41 -0
- package/src/mcp/createMcpServer.ts +53 -0
- package/src/mcp/error/buildRecovery.test.ts +37 -0
- package/src/mcp/error/buildRecovery.ts +17 -0
- package/src/mcp/error/index.ts +12 -0
- package/src/mcp/error/serializeError.test.ts +121 -0
- package/src/mcp/error/serializeError.ts +31 -0
- package/src/mcp/error/serializeErrorPayload.test.ts +38 -0
- package/src/mcp/error/serializeErrorPayload.ts +27 -0
- package/src/mcp/error/types.ts +51 -0
- package/src/mcp/index.ts +15 -0
- package/src/mcp/registerResources.test.ts +236 -0
- package/src/mcp/registerResources.ts +303 -0
- package/src/mcp/runMcpServer.test.ts +66 -0
- package/src/mcp/runMcpServer.ts +24 -0
- package/src/mcp/tools/index.ts +55 -0
- package/src/mcp/tools/registerFromSpec.ts +97 -0
- package/src/mcp/tools/registerTools.test.ts +1124 -0
- package/src/mcp/types.ts +62 -0
- package/src/mcp/utils/estimateTokens.test.ts +14 -0
- package/src/mcp/utils/estimateTokens.ts +9 -0
- package/src/mcp/utils/index.ts +11 -0
- package/src/mcp/utils/wrapTool.test.ts +108 -0
- package/src/mcp/utils/wrapTool.ts +81 -0
- package/src/package-manager/constants.ts +29 -0
- package/src/package-manager/detectInstallSource.test.ts +23 -0
- package/src/package-manager/detectInstallSource.ts +111 -0
- package/src/package-manager/detectLocalInstall.test.ts +16 -0
- package/src/package-manager/detectLocalInstall.ts +43 -0
- package/src/package-manager/detectPackageManager.test.ts +81 -0
- package/src/package-manager/detectPackageManager.ts +30 -0
- package/src/package-manager/index.ts +6 -0
- package/src/package-manager/types.ts +12 -0
- package/src/pipeline/collectCommands.test.ts +37 -0
- package/src/pipeline/collectCommands.ts +47 -0
- package/src/pipeline/constants.ts +14 -0
- package/src/pipeline/createProgram.test.ts +112 -0
- package/src/pipeline/createProgram.ts +70 -0
- package/src/pipeline/formatTerminal.test.ts +43 -0
- package/src/pipeline/formatTerminal.ts +53 -0
- package/src/pipeline/index.ts +19 -0
- package/src/pipeline/mapExitCode.test.ts +41 -0
- package/src/pipeline/mapExitCode.ts +12 -0
- package/src/pipeline/parseGlobalFlags.ts +21 -0
- package/src/pipeline/renderError.test.ts +151 -0
- package/src/pipeline/renderError.ts +114 -0
- package/src/pipeline/resolveCommandKind.test.ts +68 -0
- package/src/pipeline/resolveCommandKind.ts +71 -0
- package/src/pipeline/runCli.orchestration.test.ts +418 -0
- package/src/pipeline/runCli.test.ts +70 -0
- package/src/pipeline/runCli.ts +215 -0
- package/src/pipeline/types.ts +17 -0
- package/src/testing/cli.ts +43 -0
- package/src/testing/createTestMcpClient.ts +64 -0
- package/src/testing/dsFixtures.ts +506 -0
- package/src/testing/fixtures/canonical-config.json +4 -0
- package/src/testing/fixtures/canonical.ttl +437 -0
- package/src/testing/fixtures/filtered-config.json +4 -0
- package/src/testing/fixtures.ts +34 -0
- package/src/testing/helpers/assertParity.ts +28 -0
- package/src/testing/helpers/createTestMcpClient.ts +40 -0
- package/src/testing/helpers/createTestRuntime.ts +67 -0
- package/src/testing/index.ts +8 -0
- package/src/testing/integration/agent-session.test.ts +148 -0
- package/src/testing/integration/boot.test.ts +67 -0
- package/src/testing/integration/mcp-surface.test.ts +574 -0
- package/src/testing/integration/parity.test.ts +192 -0
- package/src/testing/store.ts +39 -0
- package/src/testing/types.ts +20 -0
package/src/constants.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-level constants for the pragma CLI.
|
|
3
|
+
*
|
|
4
|
+
* Groups program metadata (name, version, description), release channel
|
|
5
|
+
* definitions, and the cross-ontology property resolution map shared
|
|
6
|
+
* by MCP resources and domain operations.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import pkg from "../package.json" with { type: "json" };
|
|
10
|
+
import { PREFIX_MAP } from "./domains/shared/prefixes.js";
|
|
11
|
+
|
|
12
|
+
/** CLI program name used in help text and error messages. */
|
|
13
|
+
const PROGRAM_NAME = "pragma";
|
|
14
|
+
|
|
15
|
+
/** One-line program description for help text. */
|
|
16
|
+
const PROGRAM_DESCRIPTION = "CLI and MCP server for Canonical's design system.";
|
|
17
|
+
|
|
18
|
+
/** Semver version string read from package.json. */
|
|
19
|
+
const VERSION = pkg.version;
|
|
20
|
+
|
|
21
|
+
/** Allowed release channel values for the `channel` config field. */
|
|
22
|
+
const VALID_CHANNELS = ["normal", "experimental", "prerelease"] as const;
|
|
23
|
+
|
|
24
|
+
/** A release channel name. */
|
|
25
|
+
type Channel = (typeof VALID_CHANNELS)[number];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Per-namespace property URIs for semantically equivalent fields.
|
|
29
|
+
* Each ontology uses different property names for the same concept
|
|
30
|
+
* (name/label, description/summary/comment).
|
|
31
|
+
*/
|
|
32
|
+
interface OntologyPropertyMap {
|
|
33
|
+
readonly label: string;
|
|
34
|
+
readonly description?: string;
|
|
35
|
+
readonly definition?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Maps namespace prefix → property URIs for human-readable label and
|
|
40
|
+
* description. Used by MCP resource handlers and domain operations to
|
|
41
|
+
* resolve cross-ontology properties uniformly.
|
|
42
|
+
*/
|
|
43
|
+
const PROPERTY_MAP: Record<string, OntologyPropertyMap> = {
|
|
44
|
+
ds: {
|
|
45
|
+
label: `${PREFIX_MAP.ds}name`,
|
|
46
|
+
description: `${PREFIX_MAP.ds}summary`,
|
|
47
|
+
definition: `${PREFIX_MAP.ds}definition`,
|
|
48
|
+
},
|
|
49
|
+
cs: {
|
|
50
|
+
label: `${PREFIX_MAP.cs}name`,
|
|
51
|
+
description: `${PREFIX_MAP.cs}description`,
|
|
52
|
+
definition: `${PREFIX_MAP.cs}definition`,
|
|
53
|
+
},
|
|
54
|
+
rdfs: {
|
|
55
|
+
label: `${PREFIX_MAP.rdfs}label`,
|
|
56
|
+
description: `${PREFIX_MAP.rdfs}comment`,
|
|
57
|
+
},
|
|
58
|
+
owl: {
|
|
59
|
+
label: `${PREFIX_MAP.rdfs}label`,
|
|
60
|
+
description: `${PREFIX_MAP.rdfs}comment`,
|
|
61
|
+
},
|
|
62
|
+
skos: {
|
|
63
|
+
label: `${PREFIX_MAP.skos}prefLabel`,
|
|
64
|
+
definition: `${PREFIX_MAP.skos}definition`,
|
|
65
|
+
},
|
|
66
|
+
anatomy: {
|
|
67
|
+
label: `${PREFIX_MAP.ds}name`,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export {
|
|
72
|
+
PROGRAM_DESCRIPTION,
|
|
73
|
+
PROGRAM_NAME,
|
|
74
|
+
PROPERTY_MAP,
|
|
75
|
+
VALID_CHANNELS,
|
|
76
|
+
VERSION,
|
|
77
|
+
};
|
|
78
|
+
export type { Channel, OntologyPropertyMap };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { EntityDisplayConfig } from "../shared/contracts.js";
|
|
2
|
+
import { P } from "../shared/prefixes.js";
|
|
3
|
+
import type {
|
|
4
|
+
BlockDetailed,
|
|
5
|
+
BlockDigest,
|
|
6
|
+
BlockSummary,
|
|
7
|
+
FilterConfig,
|
|
8
|
+
} from "../shared/types.js";
|
|
9
|
+
|
|
10
|
+
export const blockConfig: EntityDisplayConfig<
|
|
11
|
+
BlockSummary,
|
|
12
|
+
BlockDigest,
|
|
13
|
+
BlockDetailed
|
|
14
|
+
> = {
|
|
15
|
+
domain: "block",
|
|
16
|
+
entityName: "block",
|
|
17
|
+
rdfTypes: [
|
|
18
|
+
`${P.ds}Component`,
|
|
19
|
+
`${P.ds}Pattern`,
|
|
20
|
+
`${P.ds}Layout`,
|
|
21
|
+
`${P.ds}Subcomponent`,
|
|
22
|
+
],
|
|
23
|
+
listColumns: [
|
|
24
|
+
{ key: "uri", label: "IRI" },
|
|
25
|
+
{ key: "name", label: "Name" },
|
|
26
|
+
{ key: "type", label: "Type" },
|
|
27
|
+
{ key: "tier", label: "Tier" },
|
|
28
|
+
],
|
|
29
|
+
digestColumns: [{ key: "summary", label: "Summary", showWhenEmpty: false }],
|
|
30
|
+
lookupSections: [
|
|
31
|
+
{ key: "summary", heading: "Summary", kind: "field" },
|
|
32
|
+
{ key: "whenToUse", heading: "When to use", kind: "field" },
|
|
33
|
+
{ key: "whenNotToUse", heading: "When not to use", kind: "field" },
|
|
34
|
+
{ key: "guidelines", heading: "Guidelines", kind: "field" },
|
|
35
|
+
{ key: "anatomyDsl", heading: "Anatomy (DSL)", kind: "code" },
|
|
36
|
+
{ key: "anatomyClassic", heading: "Anatomy (classic)", kind: "field" },
|
|
37
|
+
{ key: "modifierFamilies", heading: "Modifier Families", kind: "table" },
|
|
38
|
+
{ key: "properties", heading: "Properties", kind: "nested-table" },
|
|
39
|
+
{ key: "subcomponents", heading: "Subcomponents", kind: "list" },
|
|
40
|
+
{ key: "implementationPaths", heading: "Implementations", kind: "list" },
|
|
41
|
+
{ key: "tokens", heading: "Tokens", kind: "list" },
|
|
42
|
+
],
|
|
43
|
+
emptyRecovery: (_filters: FilterConfig) => ({
|
|
44
|
+
message: "List visible blocks.",
|
|
45
|
+
cli: "pragma block list",
|
|
46
|
+
mcp: { tool: "block_list" },
|
|
47
|
+
}),
|
|
48
|
+
notFoundRecovery: (_query: string) => ({
|
|
49
|
+
message: "List visible blocks.",
|
|
50
|
+
cli: "pragma block list",
|
|
51
|
+
mcp: { tool: "block_list" },
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { CommandDefinition } from "@canonical/cli-core";
|
|
2
|
+
import type { Store } from "@canonical/ke";
|
|
3
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
4
|
+
import { createTestStore, DS_ALL_TTL } from "#testing";
|
|
5
|
+
import type { PragmaContext } from "../../shared/context.js";
|
|
6
|
+
import type { BlockSummary } from "../../shared/types.js";
|
|
7
|
+
import buildListCommand from "./list.js";
|
|
8
|
+
|
|
9
|
+
let store: Store;
|
|
10
|
+
let cleanup: () => void;
|
|
11
|
+
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
const result = await createTestStore({ ttl: DS_ALL_TTL });
|
|
14
|
+
store = result.store;
|
|
15
|
+
cleanup = result.cleanup;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterAll(() => cleanup());
|
|
19
|
+
|
|
20
|
+
function makeCtx(overrides: Partial<PragmaContext> = {}): PragmaContext {
|
|
21
|
+
return {
|
|
22
|
+
cwd: "/tmp",
|
|
23
|
+
globalFlags: { llm: false, format: "text" as const, verbose: false },
|
|
24
|
+
store,
|
|
25
|
+
config: { tier: undefined, channel: "prerelease" },
|
|
26
|
+
...overrides,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function executeOutput(
|
|
31
|
+
cmd: CommandDefinition,
|
|
32
|
+
params: Record<string, unknown>,
|
|
33
|
+
ctx: PragmaContext,
|
|
34
|
+
): Promise<{ value: unknown; text: string }> {
|
|
35
|
+
const result = await cmd.execute(params, ctx);
|
|
36
|
+
expect(result.tag).toBe("output");
|
|
37
|
+
if (result.tag !== "output") throw new Error("Expected output result");
|
|
38
|
+
const text = result.render.plain(result.value);
|
|
39
|
+
return { value: result.value, text };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe("buildListCommand", () => {
|
|
43
|
+
it("returns output result with block data", async () => {
|
|
44
|
+
const ctx = makeCtx();
|
|
45
|
+
const cmd = buildListCommand(ctx);
|
|
46
|
+
const { value } = await executeOutput(cmd, {}, ctx);
|
|
47
|
+
const names = (value as BlockSummary[]).map((c) => c.name);
|
|
48
|
+
expect(names).toContain("Button");
|
|
49
|
+
expect(names).toContain("Card");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("renders plain text output", async () => {
|
|
53
|
+
const ctx = makeCtx();
|
|
54
|
+
const cmd = buildListCommand(ctx);
|
|
55
|
+
const { text } = await executeOutput(cmd, {}, ctx);
|
|
56
|
+
expect(text).toContain("Button");
|
|
57
|
+
expect(text).toContain("Card");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("renders LLM markdown", async () => {
|
|
61
|
+
const ctx = makeCtx({
|
|
62
|
+
globalFlags: { llm: true, format: "text" as const, verbose: false },
|
|
63
|
+
});
|
|
64
|
+
const cmd = buildListCommand(ctx);
|
|
65
|
+
const { text } = await executeOutput(cmd, {}, ctx);
|
|
66
|
+
expect(text).toContain("## Blocks");
|
|
67
|
+
expect(text).toContain("**Button**");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("renders JSON output", async () => {
|
|
71
|
+
const ctx = makeCtx({
|
|
72
|
+
globalFlags: { llm: false, format: "json" as const, verbose: false },
|
|
73
|
+
});
|
|
74
|
+
const cmd = buildListCommand(ctx);
|
|
75
|
+
const { text } = await executeOutput(cmd, {}, ctx);
|
|
76
|
+
const parsed = JSON.parse(text);
|
|
77
|
+
expect(Array.isArray(parsed)).toBe(true);
|
|
78
|
+
expect(parsed.some((c: BlockSummary) => c.name === "Button")).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("respects tier filter from config", async () => {
|
|
82
|
+
const ctx = makeCtx({
|
|
83
|
+
config: { tier: "global", channel: "normal" },
|
|
84
|
+
});
|
|
85
|
+
const cmd = buildListCommand(ctx);
|
|
86
|
+
const { value } = await executeOutput(cmd, {}, ctx);
|
|
87
|
+
const names = (value as BlockSummary[]).map((c) => c.name);
|
|
88
|
+
expect(names).toContain("Button");
|
|
89
|
+
expect(names).not.toContain("LXD Panel");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("--all-tiers ignores tier filter", async () => {
|
|
93
|
+
const ctx = makeCtx({
|
|
94
|
+
config: { tier: "global", channel: "prerelease" },
|
|
95
|
+
});
|
|
96
|
+
const cmd = buildListCommand(ctx);
|
|
97
|
+
const { value } = await executeOutput(cmd, { allTiers: true }, ctx);
|
|
98
|
+
const names = (value as BlockSummary[]).map((c) => c.name);
|
|
99
|
+
expect(names).toContain("Button");
|
|
100
|
+
expect(names).toContain("LXD Panel");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("returns results with combined tier + channel", async () => {
|
|
104
|
+
const ctx = makeCtx({
|
|
105
|
+
config: { tier: "apps/lxd", channel: "normal" },
|
|
106
|
+
});
|
|
107
|
+
const cmd = buildListCommand(ctx);
|
|
108
|
+
const result = await cmd.execute({}, ctx);
|
|
109
|
+
expect(result.tag).toBe("output");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wires the `pragma block list` CLI command.
|
|
3
|
+
*
|
|
4
|
+
* Lists all blocks visible under the current tier and channel filters.
|
|
5
|
+
* Supports progressive disclosure via `--digest` and `--detailed` flags,
|
|
6
|
+
* and an `--all-tiers` flag to widen the search.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type CommandDefinition,
|
|
11
|
+
type CommandResult,
|
|
12
|
+
createOutputResult,
|
|
13
|
+
} from "@canonical/cli-core";
|
|
14
|
+
import type { PragmaContext } from "../../shared/context.js";
|
|
15
|
+
import { selectFormatter } from "../../shared/formatters.js";
|
|
16
|
+
import { listFormatters } from "../formatters/index.js";
|
|
17
|
+
import { resolveBlockList } from "../orchestration/index.js";
|
|
18
|
+
|
|
19
|
+
export default function buildListCommand(
|
|
20
|
+
ctx: PragmaContext,
|
|
21
|
+
): CommandDefinition {
|
|
22
|
+
return {
|
|
23
|
+
path: ["block", "list"],
|
|
24
|
+
description: "List blocks in the design system",
|
|
25
|
+
parameters: [
|
|
26
|
+
{
|
|
27
|
+
name: "allTiers",
|
|
28
|
+
description: "Show blocks from all tiers",
|
|
29
|
+
type: "boolean",
|
|
30
|
+
default: false,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "digest",
|
|
34
|
+
description: "Show enriched summary with implementations",
|
|
35
|
+
type: "boolean",
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "detailed",
|
|
40
|
+
description: "Show full details for each block",
|
|
41
|
+
type: "boolean",
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
meta: {
|
|
46
|
+
examples: [
|
|
47
|
+
"pragma block list",
|
|
48
|
+
"pragma block list --all-tiers",
|
|
49
|
+
"pragma block list --digest",
|
|
50
|
+
"pragma block list --detailed",
|
|
51
|
+
"pragma block list --llm",
|
|
52
|
+
"pragma block list --format json",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
execute: async (
|
|
56
|
+
params: Record<string, unknown>,
|
|
57
|
+
): Promise<CommandResult> => {
|
|
58
|
+
const contract = await resolveBlockList(ctx, {
|
|
59
|
+
allTiers: params.allTiers === true,
|
|
60
|
+
digest: params.digest === true,
|
|
61
|
+
detailed: params.detailed === true,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return createOutputResult(contract.result.items, {
|
|
65
|
+
plain: selectFormatter(ctx, listFormatters),
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { CommandDefinition } from "@canonical/cli-core";
|
|
2
|
+
import type { Store } from "@canonical/ke";
|
|
3
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
4
|
+
import { PragmaError } from "#error";
|
|
5
|
+
import { createTestStore, DS_ALL_TTL } from "#testing";
|
|
6
|
+
import type { PragmaContext } from "../../shared/context.js";
|
|
7
|
+
import buildLookupCommand from "./lookup.js";
|
|
8
|
+
|
|
9
|
+
let store: Store;
|
|
10
|
+
let cleanup: () => void;
|
|
11
|
+
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
const result = await createTestStore({ ttl: DS_ALL_TTL });
|
|
14
|
+
store = result.store;
|
|
15
|
+
cleanup = result.cleanup;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterAll(() => cleanup());
|
|
19
|
+
|
|
20
|
+
function makeCtx(overrides: Partial<PragmaContext> = {}): PragmaContext {
|
|
21
|
+
return {
|
|
22
|
+
cwd: "/tmp",
|
|
23
|
+
globalFlags: { llm: false, format: "text" as const, verbose: false },
|
|
24
|
+
store,
|
|
25
|
+
config: { tier: undefined, channel: "prerelease" },
|
|
26
|
+
...overrides,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function executeOutput(
|
|
31
|
+
cmd: CommandDefinition,
|
|
32
|
+
params: Record<string, unknown>,
|
|
33
|
+
ctx: PragmaContext,
|
|
34
|
+
): Promise<{ value: unknown; text: string }> {
|
|
35
|
+
const result = await cmd.execute(params, ctx);
|
|
36
|
+
expect(result.tag).toBe("output");
|
|
37
|
+
if (result.tag !== "output") throw new Error("Expected output result");
|
|
38
|
+
const text = result.render.plain(result.value);
|
|
39
|
+
return { value: result.value, text };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
describe("buildLookupCommand", () => {
|
|
43
|
+
it("returns summary by default", async () => {
|
|
44
|
+
const ctx = makeCtx();
|
|
45
|
+
const cmd = buildLookupCommand(ctx);
|
|
46
|
+
const { text } = await executeOutput(cmd, { names: ["Button"] }, ctx);
|
|
47
|
+
expect(text).toContain("Button");
|
|
48
|
+
expect(text).toContain("global");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("returns detailed view with --detailed", async () => {
|
|
52
|
+
const ctx = makeCtx();
|
|
53
|
+
const cmd = buildLookupCommand(ctx);
|
|
54
|
+
const { text } = await executeOutput(
|
|
55
|
+
cmd,
|
|
56
|
+
{ names: ["Button"], detailed: true },
|
|
57
|
+
ctx,
|
|
58
|
+
);
|
|
59
|
+
expect(text).toContain("Button");
|
|
60
|
+
expect(text).toContain("Modifiers");
|
|
61
|
+
expect(text).toContain("importance");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("shows only selected aspects (--modifiers)", async () => {
|
|
65
|
+
const ctx = makeCtx();
|
|
66
|
+
const cmd = buildLookupCommand(ctx);
|
|
67
|
+
const { text } = await executeOutput(
|
|
68
|
+
cmd,
|
|
69
|
+
{ names: ["Button"], modifiers: true },
|
|
70
|
+
ctx,
|
|
71
|
+
);
|
|
72
|
+
expect(text).toContain("Modifiers");
|
|
73
|
+
expect(text).toContain("importance");
|
|
74
|
+
// Summary field "Tokens: 1" is always shown, but token details should not appear
|
|
75
|
+
expect(text).not.toContain("color.primary");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("composes aspect flags (--modifiers --tokens)", async () => {
|
|
79
|
+
const ctx = makeCtx();
|
|
80
|
+
const cmd = buildLookupCommand(ctx);
|
|
81
|
+
const { text } = await executeOutput(
|
|
82
|
+
cmd,
|
|
83
|
+
{ names: ["Button"], modifiers: true, tokens: true },
|
|
84
|
+
ctx,
|
|
85
|
+
);
|
|
86
|
+
expect(text).toContain("Modifiers");
|
|
87
|
+
expect(text).toContain("Tokens");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("renders LLM markdown", async () => {
|
|
91
|
+
const ctx = makeCtx({
|
|
92
|
+
globalFlags: { llm: true, format: "text" as const, verbose: false },
|
|
93
|
+
});
|
|
94
|
+
const cmd = buildLookupCommand(ctx);
|
|
95
|
+
const { text } = await executeOutput(cmd, { names: ["Button"] }, ctx);
|
|
96
|
+
expect(text).toContain("## Button");
|
|
97
|
+
expect(text).toContain("Tier: global");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("renders JSON", async () => {
|
|
101
|
+
const ctx = makeCtx({
|
|
102
|
+
globalFlags: { llm: false, format: "json" as const, verbose: false },
|
|
103
|
+
});
|
|
104
|
+
const cmd = buildLookupCommand(ctx);
|
|
105
|
+
const { text } = await executeOutput(cmd, { names: ["Button"] }, ctx);
|
|
106
|
+
const parsed = JSON.parse(text);
|
|
107
|
+
expect(parsed.name).toBe("Button");
|
|
108
|
+
expect(parsed.tier).toBe("global");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("renders JSON with detailed aspects", async () => {
|
|
112
|
+
const ctx = makeCtx({
|
|
113
|
+
globalFlags: { llm: false, format: "json" as const, verbose: false },
|
|
114
|
+
});
|
|
115
|
+
const cmd = buildLookupCommand(ctx);
|
|
116
|
+
const { text } = await executeOutput(
|
|
117
|
+
cmd,
|
|
118
|
+
{ names: ["Button"], detailed: true },
|
|
119
|
+
ctx,
|
|
120
|
+
);
|
|
121
|
+
const parsed = JSON.parse(text);
|
|
122
|
+
expect(parsed.modifierValues).toBeDefined();
|
|
123
|
+
expect(parsed.tokens).toBeDefined();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("populates nodeCount from anatomy nodes", async () => {
|
|
127
|
+
const ctx = makeCtx({
|
|
128
|
+
globalFlags: { llm: false, format: "json" as const, verbose: false },
|
|
129
|
+
});
|
|
130
|
+
const cmd = buildLookupCommand(ctx);
|
|
131
|
+
const { text } = await executeOutput(cmd, { names: ["Button"] }, ctx);
|
|
132
|
+
const parsed = JSON.parse(text);
|
|
133
|
+
expect(parsed.nodeCount).toBe(3);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("renders multiple lookup results together", async () => {
|
|
137
|
+
const ctx = makeCtx();
|
|
138
|
+
const cmd = buildLookupCommand(ctx);
|
|
139
|
+
const { text } = await executeOutput(
|
|
140
|
+
cmd,
|
|
141
|
+
{ names: ["Button", "Card"] },
|
|
142
|
+
ctx,
|
|
143
|
+
);
|
|
144
|
+
expect(text).toContain("Button");
|
|
145
|
+
expect(text).toContain("Card");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("throws ENTITY_NOT_FOUND for unknown block", async () => {
|
|
149
|
+
const ctx = makeCtx();
|
|
150
|
+
const cmd = buildLookupCommand(ctx);
|
|
151
|
+
const result = await cmd.execute({ names: ["NonExistent"] }, ctx);
|
|
152
|
+
expect(result.tag).toBe("output");
|
|
153
|
+
|
|
154
|
+
if (result.tag !== "output") {
|
|
155
|
+
expect.fail("Expected output result");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const text = result.render.plain(result.value);
|
|
159
|
+
expect(text).toContain("Errors:");
|
|
160
|
+
expect(text).toContain("NonExistent");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("throws INVALID_INPUT for empty name", async () => {
|
|
164
|
+
const ctx = makeCtx();
|
|
165
|
+
const cmd = buildLookupCommand(ctx);
|
|
166
|
+
await expect(cmd.execute({ names: [] }, ctx)).rejects.toThrow(PragmaError);
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
await cmd.execute({ names: [] }, ctx);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
expect(e).toBeInstanceOf(PragmaError);
|
|
172
|
+
expect((e as PragmaError).code).toBe("INVALID_INPUT");
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("provides tab completion candidates", async () => {
|
|
177
|
+
const ctx = makeCtx();
|
|
178
|
+
const cmd = buildLookupCommand(ctx);
|
|
179
|
+
const nameParam = cmd.parameters.find((p) => p.name === "names");
|
|
180
|
+
expect(nameParam?.complete).toBeDefined();
|
|
181
|
+
|
|
182
|
+
if (nameParam?.complete) {
|
|
183
|
+
const candidates = await nameParam.complete("Bu", ctx);
|
|
184
|
+
expect(candidates).toContain("Button");
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wires the `pragma block lookup <name-or-uri...>` CLI command.
|
|
3
|
+
*
|
|
4
|
+
* Accepts a positional block name or IRI and optional aspect flags (anatomy,
|
|
5
|
+
* modifiers, tokens, implementations). Delegates to {@link lookupBlock} for
|
|
6
|
+
* data retrieval and {@link lookupFormatters} for output rendering.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
type CommandDefinition,
|
|
11
|
+
type CommandResult,
|
|
12
|
+
createOutputResult,
|
|
13
|
+
} from "@canonical/cli-core";
|
|
14
|
+
import { PragmaError } from "#error";
|
|
15
|
+
import type { PragmaContext } from "../../shared/context.js";
|
|
16
|
+
import type { LookupResult } from "../../shared/contracts.js";
|
|
17
|
+
import { lookupFormatters } from "../formatters/index.js";
|
|
18
|
+
import { resolveAspects } from "../helpers/index.js";
|
|
19
|
+
import { listBlocks, type lookupBlock } from "../operations/index.js";
|
|
20
|
+
import {
|
|
21
|
+
buildBlockFilters,
|
|
22
|
+
resolveBlockLookup,
|
|
23
|
+
} from "../orchestration/index.js";
|
|
24
|
+
import type { AspectFlags } from "../types.js";
|
|
25
|
+
|
|
26
|
+
interface BlockLookupOutput {
|
|
27
|
+
readonly result: LookupResult<Awaited<ReturnType<typeof lookupBlock>>>;
|
|
28
|
+
readonly detailed: boolean;
|
|
29
|
+
readonly aspects: AspectFlags;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default function buildLookupCommand(
|
|
33
|
+
ctx: PragmaContext,
|
|
34
|
+
): CommandDefinition {
|
|
35
|
+
return {
|
|
36
|
+
path: ["block", "lookup"],
|
|
37
|
+
description: "Look up block details",
|
|
38
|
+
parameters: [
|
|
39
|
+
{
|
|
40
|
+
name: "names",
|
|
41
|
+
description: "Block names or IRIs",
|
|
42
|
+
type: "multiselect",
|
|
43
|
+
positional: true,
|
|
44
|
+
required: true,
|
|
45
|
+
complete: async (partial: string) => {
|
|
46
|
+
const all = await listBlocks(ctx.store, ctx.config);
|
|
47
|
+
return all
|
|
48
|
+
.map((c) => c.name)
|
|
49
|
+
.filter((n) => n.toLowerCase().startsWith(partial.toLowerCase()));
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "detailed",
|
|
54
|
+
description:
|
|
55
|
+
"Show full details including anatomy, modifiers, tokens, and implementations",
|
|
56
|
+
type: "boolean",
|
|
57
|
+
default: false,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "anatomy",
|
|
61
|
+
description: "Show anatomy tree",
|
|
62
|
+
type: "boolean",
|
|
63
|
+
default: false,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "modifiers",
|
|
67
|
+
description: "Show modifier values",
|
|
68
|
+
type: "boolean",
|
|
69
|
+
default: false,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "tokens",
|
|
73
|
+
description: "Show token references",
|
|
74
|
+
type: "boolean",
|
|
75
|
+
default: false,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "implementations",
|
|
79
|
+
description: "Show implementation paths",
|
|
80
|
+
type: "boolean",
|
|
81
|
+
default: false,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
parameterGroups: {
|
|
85
|
+
"Aspect filters": ["anatomy", "modifiers", "tokens", "implementations"],
|
|
86
|
+
},
|
|
87
|
+
meta: {
|
|
88
|
+
examples: [
|
|
89
|
+
"pragma block lookup Button",
|
|
90
|
+
"pragma block lookup Button Card",
|
|
91
|
+
"pragma block lookup Button --detailed",
|
|
92
|
+
"pragma block lookup Button --anatomy --modifiers",
|
|
93
|
+
"pragma block lookup Button --detailed --llm",
|
|
94
|
+
"pragma block lookup ds:global.component.button",
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
execute: async (
|
|
98
|
+
params: Record<string, unknown>,
|
|
99
|
+
): Promise<CommandResult> => {
|
|
100
|
+
const names = normalizeNames(params.names, params.name);
|
|
101
|
+
if (names.length === 0) {
|
|
102
|
+
throw PragmaError.invalidInput("names", "(empty)", {
|
|
103
|
+
recovery: {
|
|
104
|
+
message: "List available blocks.",
|
|
105
|
+
cli: "pragma block list",
|
|
106
|
+
mcp: { tool: "block_list" },
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const detailed = params.detailed === true;
|
|
112
|
+
const aspectInput: Partial<AspectFlags> = {
|
|
113
|
+
anatomy: params.anatomy === true,
|
|
114
|
+
modifiers: params.modifiers === true,
|
|
115
|
+
tokens: params.tokens === true,
|
|
116
|
+
implementations: params.implementations === true,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const isAspectSelected =
|
|
120
|
+
aspectInput.anatomy ||
|
|
121
|
+
aspectInput.modifiers ||
|
|
122
|
+
aspectInput.tokens ||
|
|
123
|
+
aspectInput.implementations;
|
|
124
|
+
const showDetailed = detailed || (isAspectSelected ?? false);
|
|
125
|
+
const aspects = resolveAspects(aspectInput);
|
|
126
|
+
|
|
127
|
+
const contract = await resolveBlockLookup(
|
|
128
|
+
ctx.store,
|
|
129
|
+
names,
|
|
130
|
+
buildBlockFilters(ctx),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
return createOutputResult<BlockLookupOutput>(
|
|
134
|
+
{ result: contract.result, detailed: showDetailed, aspects },
|
|
135
|
+
{ plain: renderBlockLookupOutput(ctx) },
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function normalizeNames(names: unknown, legacyName?: unknown): string[] {
|
|
142
|
+
if (Array.isArray(names)) {
|
|
143
|
+
return names.filter(
|
|
144
|
+
(name): name is string => typeof name === "string" && name.length > 0,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (typeof legacyName === "string" && legacyName.length > 0) {
|
|
148
|
+
return [legacyName];
|
|
149
|
+
}
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function renderBlockLookupOutput(
|
|
154
|
+
ctx: PragmaContext,
|
|
155
|
+
): (data: BlockLookupOutput) => string {
|
|
156
|
+
return ({ result, detailed, aspects }) => {
|
|
157
|
+
const formatOne =
|
|
158
|
+
ctx.globalFlags.format === "json"
|
|
159
|
+
? lookupFormatters.json
|
|
160
|
+
: ctx.globalFlags.llm
|
|
161
|
+
? lookupFormatters.llm
|
|
162
|
+
: lookupFormatters.plain;
|
|
163
|
+
|
|
164
|
+
if (ctx.globalFlags.format === "json") {
|
|
165
|
+
if (result.results.length === 1 && result.errors.length === 0) {
|
|
166
|
+
const only = result.results[0];
|
|
167
|
+
return only
|
|
168
|
+
? lookupFormatters.json({ block: only, detailed, aspects })
|
|
169
|
+
: JSON.stringify({ results: [], errors: result.errors }, null, 2);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return JSON.stringify(
|
|
173
|
+
{
|
|
174
|
+
results: result.results.map((block) =>
|
|
175
|
+
JSON.parse(lookupFormatters.json({ block, detailed, aspects })),
|
|
176
|
+
),
|
|
177
|
+
errors: result.errors,
|
|
178
|
+
},
|
|
179
|
+
null,
|
|
180
|
+
2,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const parts = result.results.map((block) =>
|
|
185
|
+
formatOne({ block, detailed, aspects }),
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
if (result.errors.length > 0) {
|
|
189
|
+
parts.push(
|
|
190
|
+
[
|
|
191
|
+
"Errors:",
|
|
192
|
+
...result.errors.map((error) => `- ${error.query}: ${error.message}`),
|
|
193
|
+
].join("\n"),
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return parts.join("\n\n");
|
|
198
|
+
};
|
|
199
|
+
}
|