@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
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-mode formatter factory for `pragma token lookup` output.
|
|
3
|
+
*
|
|
4
|
+
* - **plain** — terminal text showing token name, category, and optional
|
|
5
|
+
* per-theme values when detailed.
|
|
6
|
+
* - **llm** — condensed Markdown consumed by LLM agents and reused
|
|
7
|
+
* by the MCP adapter when `condensed: true`.
|
|
8
|
+
* - **json** — structured JSON; omits values unless detailed.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Formatters } from "../../shared/formatters.js";
|
|
12
|
+
import type { TokenDetailed } from "../../shared/types.js";
|
|
13
|
+
|
|
14
|
+
/** Options controlling detail level for the token-lookup formatter. */
|
|
15
|
+
export interface TokenLookupFormatterOptions {
|
|
16
|
+
readonly detailed: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates a three-mode formatter set for a single token, capturing the
|
|
21
|
+
* detail level in the closure so callers only pass the token data.
|
|
22
|
+
*
|
|
23
|
+
* @param options - detail-level options
|
|
24
|
+
* @returns plain/llm/json formatters for {@link TokenDetailed}
|
|
25
|
+
*/
|
|
26
|
+
export function createLookupFormatters(
|
|
27
|
+
options: TokenLookupFormatterOptions,
|
|
28
|
+
): Formatters<TokenDetailed> {
|
|
29
|
+
const { detailed } = options;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
plain: (token) => {
|
|
33
|
+
const lines: string[] = [];
|
|
34
|
+
lines.push(token.name);
|
|
35
|
+
lines.push(`Category: ${token.category || "—"}`);
|
|
36
|
+
|
|
37
|
+
if (detailed && token.values.length > 0) {
|
|
38
|
+
lines.push("");
|
|
39
|
+
lines.push("Values:");
|
|
40
|
+
for (const v of token.values) {
|
|
41
|
+
lines.push(` ${v.theme}: ${v.value}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return lines.join("\n");
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
llm: (token) => {
|
|
49
|
+
const lines: string[] = [];
|
|
50
|
+
lines.push(`## ${token.name}`);
|
|
51
|
+
lines.push(`Category: ${token.category || "—"}`);
|
|
52
|
+
|
|
53
|
+
if (detailed && token.values.length > 0) {
|
|
54
|
+
lines.push("");
|
|
55
|
+
lines.push("### Values");
|
|
56
|
+
for (const v of token.values) {
|
|
57
|
+
lines.push(`- ${v.theme}: \`${v.value}\``);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return lines.join("\n");
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
json: (token) => {
|
|
65
|
+
if (detailed) {
|
|
66
|
+
return JSON.stringify(token, null, 2);
|
|
67
|
+
}
|
|
68
|
+
const { values: _values, ...summary } = token;
|
|
69
|
+
return JSON.stringify(summary, null, 2);
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Token domain — CLI commands and operations.
|
|
3
|
+
*
|
|
4
|
+
* Commands: `pragma token list`, `pragma token lookup <name>`,
|
|
5
|
+
* `pragma tokens add-config`.
|
|
6
|
+
* Operations: {@link lookupToken}, {@link listTokens}, {@link resolveAddConfig}.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CommandDefinition } from "@canonical/cli-core";
|
|
10
|
+
import type { PragmaContext } from "../shared/context.js";
|
|
11
|
+
import {
|
|
12
|
+
addConfigCommand,
|
|
13
|
+
listCommand,
|
|
14
|
+
lookupCommand,
|
|
15
|
+
} from "./commands/index.js";
|
|
16
|
+
|
|
17
|
+
export function commands(ctx: PragmaContext): CommandDefinition[] {
|
|
18
|
+
return [listCommand(ctx), lookupCommand(ctx), addConfigCommand()];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { specs as mcpSpecs } from "./mcp/index.js";
|
|
22
|
+
export type { AddConfigResult, TokenListFilters } from "./operations/index.js";
|
|
23
|
+
export {
|
|
24
|
+
listTokens,
|
|
25
|
+
lookupToken,
|
|
26
|
+
resolveAddConfig,
|
|
27
|
+
} from "./operations/index.js";
|
|
28
|
+
export {
|
|
29
|
+
resolveTokenList,
|
|
30
|
+
resolveTokenLookup,
|
|
31
|
+
tokenEmptyError,
|
|
32
|
+
} from "./orchestration/index.js";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool specs for the token domain.
|
|
3
|
+
*
|
|
4
|
+
* Declarative definitions — no MCP imports. The adapter layer
|
|
5
|
+
* converts these into registered MCP tools via `registerFromSpec()`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { writeFileSync } from "node:fs";
|
|
9
|
+
import { PragmaError } from "#error";
|
|
10
|
+
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
11
|
+
import {
|
|
12
|
+
createLookupFormatters as createTokenLookupFmt,
|
|
13
|
+
listFormatters as tokenListFmt,
|
|
14
|
+
} from "../formatters/index.js";
|
|
15
|
+
import { resolveAddConfig } from "../operations/index.js";
|
|
16
|
+
import {
|
|
17
|
+
resolveTokenList,
|
|
18
|
+
resolveTokenLookup,
|
|
19
|
+
} from "../orchestration/index.js";
|
|
20
|
+
|
|
21
|
+
const specs: readonly ToolSpec[] = [
|
|
22
|
+
{
|
|
23
|
+
name: "token_list",
|
|
24
|
+
description:
|
|
25
|
+
"List all design tokens. Optionally filter by category (token type).",
|
|
26
|
+
params: {
|
|
27
|
+
category: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "Filter by token type (e.g., Color, Dimension)",
|
|
30
|
+
optional: true,
|
|
31
|
+
},
|
|
32
|
+
condensed: {
|
|
33
|
+
type: "boolean",
|
|
34
|
+
description: "Token-optimized output",
|
|
35
|
+
optional: true,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
readOnly: true,
|
|
39
|
+
async execute(rt, { category, condensed }) {
|
|
40
|
+
const resolution = await resolveTokenList(rt, {
|
|
41
|
+
category: category as string | undefined,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (condensed) {
|
|
45
|
+
const text = tokenListFmt.llm([...resolution.items]);
|
|
46
|
+
return {
|
|
47
|
+
condensed: true,
|
|
48
|
+
text,
|
|
49
|
+
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
data: resolution.items,
|
|
55
|
+
meta: { count: resolution.items.length },
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
{
|
|
61
|
+
name: "token_lookup",
|
|
62
|
+
description:
|
|
63
|
+
"Get detailed information about one or more design tokens including theme values.",
|
|
64
|
+
params: {
|
|
65
|
+
names: {
|
|
66
|
+
type: "string[]",
|
|
67
|
+
description: "Token names or IRIs to look up (e.g. ['color.primary'])",
|
|
68
|
+
optional: false,
|
|
69
|
+
},
|
|
70
|
+
condensed: {
|
|
71
|
+
type: "boolean",
|
|
72
|
+
description: "Token-optimized output",
|
|
73
|
+
optional: true,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
readOnly: true,
|
|
77
|
+
async execute(rt, { names, condensed }) {
|
|
78
|
+
const contract = await resolveTokenLookup(rt.store, names as string[]);
|
|
79
|
+
const result = contract.result;
|
|
80
|
+
|
|
81
|
+
if (condensed) {
|
|
82
|
+
const fmt = createTokenLookupFmt({ detailed: true });
|
|
83
|
+
const textParts = result.results.map((token) => fmt.llm(token));
|
|
84
|
+
|
|
85
|
+
if (result.errors.length > 0) {
|
|
86
|
+
textParts.push(
|
|
87
|
+
[
|
|
88
|
+
"### Errors",
|
|
89
|
+
...result.errors.map(
|
|
90
|
+
(error) => `- ${error.query}: ${error.message}`,
|
|
91
|
+
),
|
|
92
|
+
].join("\n"),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
condensed: true,
|
|
98
|
+
text: textParts.join("\n\n"),
|
|
99
|
+
tokens: `~${Math.ceil(textParts.join("\n\n").length / 4)}`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { data: result, meta: { count: result.results.length } };
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
{
|
|
108
|
+
name: "tokens_add_config",
|
|
109
|
+
description:
|
|
110
|
+
"Generate a tokens.config.mjs file for terrazzo token pipeline.",
|
|
111
|
+
params: {
|
|
112
|
+
force: {
|
|
113
|
+
type: "boolean",
|
|
114
|
+
description: "Overwrite existing config file",
|
|
115
|
+
optional: true,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
readOnly: false,
|
|
119
|
+
async execute(rt, { force }) {
|
|
120
|
+
const result = resolveAddConfig(rt.cwd);
|
|
121
|
+
|
|
122
|
+
if (result.alreadyExists && !force) {
|
|
123
|
+
throw PragmaError.invalidInput("tokens.config.mjs", "already exists", {
|
|
124
|
+
recovery: {
|
|
125
|
+
message: "Overwrite existing config file.",
|
|
126
|
+
cli: "pragma tokens add-config --force",
|
|
127
|
+
mcp: { tool: "tokens_add_config", params: { force: true } },
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
writeFileSync(result.configPath, result.configContent, "utf-8");
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
data: {
|
|
136
|
+
configPath: result.configPath,
|
|
137
|
+
tokenSources: result.tokenSources,
|
|
138
|
+
installHint: result.installHint,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
] as const;
|
|
144
|
+
|
|
145
|
+
export default specs;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import resolveAddConfig from "./add-config.js";
|
|
6
|
+
|
|
7
|
+
describe("resolveAddConfig", () => {
|
|
8
|
+
it("returns correct config path", () => {
|
|
9
|
+
const cwd = mkdtempSync(join(tmpdir(), "pragma-test-"));
|
|
10
|
+
try {
|
|
11
|
+
const result = resolveAddConfig(cwd);
|
|
12
|
+
expect(result.configPath).toBe(join(cwd, "tokens.config.mjs"));
|
|
13
|
+
} finally {
|
|
14
|
+
rmSync(cwd, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("returns alreadyExists: false when file does not exist", () => {
|
|
19
|
+
const cwd = mkdtempSync(join(tmpdir(), "pragma-test-"));
|
|
20
|
+
try {
|
|
21
|
+
const result = resolveAddConfig(cwd);
|
|
22
|
+
expect(result.alreadyExists).toBe(false);
|
|
23
|
+
} finally {
|
|
24
|
+
rmSync(cwd, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns alreadyExists: true when file exists", () => {
|
|
29
|
+
const cwd = mkdtempSync(join(tmpdir(), "pragma-test-"));
|
|
30
|
+
try {
|
|
31
|
+
writeFileSync(join(cwd, "tokens.config.mjs"), "// existing", "utf-8");
|
|
32
|
+
const result = resolveAddConfig(cwd);
|
|
33
|
+
expect(result.alreadyExists).toBe(true);
|
|
34
|
+
} finally {
|
|
35
|
+
rmSync(cwd, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("config content contains defineConfig", () => {
|
|
40
|
+
const cwd = mkdtempSync(join(tmpdir(), "pragma-test-"));
|
|
41
|
+
try {
|
|
42
|
+
const result = resolveAddConfig(cwd);
|
|
43
|
+
expect(result.configContent).toContain("defineConfig");
|
|
44
|
+
} finally {
|
|
45
|
+
rmSync(cwd, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("token sources include ds-global path", () => {
|
|
50
|
+
const cwd = mkdtempSync(join(tmpdir(), "pragma-test-"));
|
|
51
|
+
try {
|
|
52
|
+
const result = resolveAddConfig(cwd);
|
|
53
|
+
expect(result.tokenSources[0]).toContain("@canonical/ds-global");
|
|
54
|
+
} finally {
|
|
55
|
+
rmSync(cwd, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("provides install hint for terrazzo-lsp", () => {
|
|
60
|
+
const cwd = mkdtempSync(join(tmpdir(), "pragma-test-"));
|
|
61
|
+
try {
|
|
62
|
+
const result = resolveAddConfig(cwd);
|
|
63
|
+
expect(result.installHint).toContain("terrazzo-lsp");
|
|
64
|
+
} finally {
|
|
65
|
+
rmSync(cwd, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the terrazzo tokens config content and target path.
|
|
3
|
+
*
|
|
4
|
+
* Performs filesystem checks and package-manager detection but does not
|
|
5
|
+
* write files itself -- the caller is responsible for writing.
|
|
6
|
+
*
|
|
7
|
+
* @note Impure
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { resolve } from "node:path";
|
|
12
|
+
import { detectPackageManager, PM_COMMANDS } from "#package-manager";
|
|
13
|
+
|
|
14
|
+
/** Result of resolving a tokens config, including content and write metadata. */
|
|
15
|
+
export interface AddConfigResult {
|
|
16
|
+
readonly configPath: string;
|
|
17
|
+
readonly configContent: string;
|
|
18
|
+
readonly tokenSources: readonly string[];
|
|
19
|
+
readonly alreadyExists: boolean;
|
|
20
|
+
readonly installHint: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the tokens config to generate.
|
|
25
|
+
*
|
|
26
|
+
* Returns data only — the caller writes the file.
|
|
27
|
+
*/
|
|
28
|
+
export default function resolveAddConfig(cwd: string): AddConfigResult {
|
|
29
|
+
const configPath = resolve(cwd, "tokens.config.mjs");
|
|
30
|
+
const alreadyExists = existsSync(configPath);
|
|
31
|
+
|
|
32
|
+
const tokenSources = ["node_modules/@canonical/ds-global/tokens/**/*.json"];
|
|
33
|
+
|
|
34
|
+
const configContent = generateConfigContent(tokenSources);
|
|
35
|
+
|
|
36
|
+
const pm = detectPackageManager();
|
|
37
|
+
const installHint = `Recommended: ${PM_COMMANDS[pm].install("@canonical/terrazzo-lsp")}`;
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
configPath,
|
|
41
|
+
configContent,
|
|
42
|
+
tokenSources,
|
|
43
|
+
alreadyExists,
|
|
44
|
+
installHint,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function generateConfigContent(sources: readonly string[]): string {
|
|
49
|
+
const sourcesStr = sources.map((s) => ` "${s}"`).join(",\n");
|
|
50
|
+
return `// tokens.config.mjs — generated by pragma tokens add-config
|
|
51
|
+
import { defineConfig } from "@canonical/terrazzo";
|
|
52
|
+
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
tokens: [
|
|
55
|
+
${sourcesStr},
|
|
56
|
+
],
|
|
57
|
+
outDir: "./tokens/",
|
|
58
|
+
plugins: [],
|
|
59
|
+
});
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @module Re-exports token operations and types (`resolveAddConfig`, `getToken`, `listTokens`). */
|
|
2
|
+
|
|
3
|
+
export type { AddConfigResult } from "./add-config.js";
|
|
4
|
+
export { default as resolveAddConfig } from "./add-config.js";
|
|
5
|
+
export type { TokenListFilters } from "./list.js";
|
|
6
|
+
export { default as listTokens } from "./list.js";
|
|
7
|
+
export { default as lookupToken } from "./lookup.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
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 listTokens from "./list.js";
|
|
5
|
+
|
|
6
|
+
let store: Store;
|
|
7
|
+
let cleanup: () => void;
|
|
8
|
+
|
|
9
|
+
beforeAll(async () => {
|
|
10
|
+
const result = await createTestStore({ ttl: DS_ALL_TTL });
|
|
11
|
+
store = result.store;
|
|
12
|
+
cleanup = result.cleanup;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterAll(() => cleanup());
|
|
16
|
+
|
|
17
|
+
describe("listTokens", () => {
|
|
18
|
+
it("returns all tokens", async () => {
|
|
19
|
+
const result = await listTokens(store);
|
|
20
|
+
const names = result.map((t) => t.name);
|
|
21
|
+
expect(names).toContain("color.primary");
|
|
22
|
+
expect(names).toContain("spacing.sm");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns sorted by tokenId", async () => {
|
|
26
|
+
const result = await listTokens(store);
|
|
27
|
+
const names = result.map((t) => t.name);
|
|
28
|
+
const sorted = [...names].sort();
|
|
29
|
+
expect(names).toEqual(sorted);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("filters by category", async () => {
|
|
33
|
+
const result = await listTokens(store, { category: "Color" });
|
|
34
|
+
const names = result.map((t) => t.name);
|
|
35
|
+
expect(names).toContain("color.primary");
|
|
36
|
+
expect(names).not.toContain("spacing.sm");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("category filter is case-insensitive", async () => {
|
|
40
|
+
const result = await listTokens(store, { category: "color" });
|
|
41
|
+
const names = result.map((t) => t.name);
|
|
42
|
+
expect(names).toContain("color.primary");
|
|
43
|
+
expect(names).not.toContain("spacing.sm");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns empty for non-matching category", async () => {
|
|
47
|
+
const result = await listTokens(store, { category: "nonexistent" });
|
|
48
|
+
expect(result).toEqual([]);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lists all design tokens, optionally filtered by category (token type name).
|
|
3
|
+
*
|
|
4
|
+
* @param store - ke store to query
|
|
5
|
+
* @param filters - optional category filter
|
|
6
|
+
* @returns array of token summaries ordered by token ID, empty when none match
|
|
7
|
+
* @note Queries ke store
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Store, URI } from "@canonical/ke";
|
|
11
|
+
import { escapeSparqlValue } from "@canonical/ke";
|
|
12
|
+
import { buildQuery } from "../../shared/buildQuery.js";
|
|
13
|
+
import { P } from "../../shared/prefixes.js";
|
|
14
|
+
import type { TokenSummary } from "../../shared/types.js";
|
|
15
|
+
|
|
16
|
+
/** Optional filters for the token list operation. */
|
|
17
|
+
export interface TokenListFilters {
|
|
18
|
+
readonly category?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default async function listTokens(
|
|
22
|
+
store: Store,
|
|
23
|
+
filters?: TokenListFilters,
|
|
24
|
+
): Promise<TokenSummary[]> {
|
|
25
|
+
const categoryFilter = filters?.category
|
|
26
|
+
? `FILTER(LCASE(?typeName) = LCASE(${escapeSparqlValue(filters.category)}))`
|
|
27
|
+
: "";
|
|
28
|
+
|
|
29
|
+
const result = await store.query(
|
|
30
|
+
buildQuery(`
|
|
31
|
+
SELECT ?token ?tokenId ?typeName
|
|
32
|
+
WHERE {
|
|
33
|
+
?token a ${P.ds}Token ;
|
|
34
|
+
${P.ds}tokenId ?tokenId .
|
|
35
|
+
OPTIONAL {
|
|
36
|
+
?token ${P.ds}tokenType ?type .
|
|
37
|
+
?type ${P.rdfs}label ?typeName .
|
|
38
|
+
}
|
|
39
|
+
${categoryFilter}
|
|
40
|
+
}
|
|
41
|
+
ORDER BY ?tokenId
|
|
42
|
+
`),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (result.type !== "select") return [];
|
|
46
|
+
|
|
47
|
+
return result.bindings.map((b) => ({
|
|
48
|
+
uri: (b.token ?? "") as URI,
|
|
49
|
+
name: b.tokenId ?? "",
|
|
50
|
+
category: b.typeName ?? "",
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Store } from "@canonical/ke";
|
|
2
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
3
|
+
import { PragmaError } from "#error";
|
|
4
|
+
import { createTestStore, DS_ALL_TTL } from "#testing";
|
|
5
|
+
import lookupToken from "./lookup.js";
|
|
6
|
+
|
|
7
|
+
let store: Store;
|
|
8
|
+
let cleanup: () => void;
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
const result = await createTestStore({ ttl: DS_ALL_TTL });
|
|
12
|
+
store = result.store;
|
|
13
|
+
cleanup = result.cleanup;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(() => cleanup());
|
|
17
|
+
|
|
18
|
+
describe("lookupToken", () => {
|
|
19
|
+
it("returns detailed data with theme values", async () => {
|
|
20
|
+
const result = await lookupToken(store, "color.primary");
|
|
21
|
+
expect(result.name).toBe("color.primary");
|
|
22
|
+
expect(result.values.length).toBe(2);
|
|
23
|
+
|
|
24
|
+
const light = result.values.find((v) => v.theme === "light");
|
|
25
|
+
expect(light?.value).toBe("#0066cc");
|
|
26
|
+
|
|
27
|
+
const dark = result.values.find((v) => v.theme === "dark");
|
|
28
|
+
expect(dark?.value).toBe("#4d9aff");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("throws PragmaError.notFound for unknown token", async () => {
|
|
32
|
+
await expect(lookupToken(store, "nonexistent")).rejects.toThrow(
|
|
33
|
+
PragmaError,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
await lookupToken(store, "nonexistent");
|
|
38
|
+
} catch (e) {
|
|
39
|
+
expect((e as PragmaError).code).toBe("ENTITY_NOT_FOUND");
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Look up detailed information for a single design token by name.
|
|
3
|
+
*
|
|
4
|
+
* Queries the token URI, type, and per-theme values (light/dark).
|
|
5
|
+
*
|
|
6
|
+
* @param store - ke store to query
|
|
7
|
+
* @param name - token name (e.g. "color.primary")
|
|
8
|
+
* @returns full token detail including theme values
|
|
9
|
+
* @throws PragmaError.notFound if the token does not exist
|
|
10
|
+
* @note Queries ke store
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Store, URI } from "@canonical/ke";
|
|
14
|
+
import { escapeSparqlValue } from "@canonical/ke";
|
|
15
|
+
import { PragmaError } from "#error";
|
|
16
|
+
import { buildQuery } from "../../shared/buildQuery.js";
|
|
17
|
+
import { P } from "../../shared/prefixes.js";
|
|
18
|
+
import type { TokenDetailed } from "../../shared/types.js";
|
|
19
|
+
|
|
20
|
+
export default async function lookupToken(
|
|
21
|
+
store: Store,
|
|
22
|
+
name: string,
|
|
23
|
+
): Promise<TokenDetailed> {
|
|
24
|
+
const escaped = escapeSparqlValue(name);
|
|
25
|
+
|
|
26
|
+
const result = await store.query(
|
|
27
|
+
buildQuery(`
|
|
28
|
+
SELECT ?token ?typeName ?valueLight ?valueDark
|
|
29
|
+
WHERE {
|
|
30
|
+
?token a ${P.ds}Token ;
|
|
31
|
+
${P.ds}tokenId ${escaped} .
|
|
32
|
+
OPTIONAL {
|
|
33
|
+
?token ${P.ds}tokenType ?type .
|
|
34
|
+
?type ${P.rdfs}label ?typeName .
|
|
35
|
+
}
|
|
36
|
+
OPTIONAL { ?token ${P.ds}valueLight ?valueLight }
|
|
37
|
+
OPTIONAL { ?token ${P.ds}valueDark ?valueDark }
|
|
38
|
+
}
|
|
39
|
+
LIMIT 1
|
|
40
|
+
`),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (result.type !== "select" || result.bindings.length === 0) {
|
|
44
|
+
throw PragmaError.notFound("token", name, {
|
|
45
|
+
recovery: {
|
|
46
|
+
message: "List available tokens.",
|
|
47
|
+
cli: "pragma token list",
|
|
48
|
+
mcp: { tool: "token_list" },
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Safe: length check above guarantees bindings[0] exists
|
|
54
|
+
const b = result.bindings[0] as (typeof result.bindings)[number];
|
|
55
|
+
|
|
56
|
+
const values: { theme: string; value: string }[] = [];
|
|
57
|
+
if (b.valueLight) values.push({ theme: "light", value: b.valueLight });
|
|
58
|
+
if (b.valueDark) values.push({ theme: "dark", value: b.valueDark });
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
uri: (b.token ?? "") as URI,
|
|
62
|
+
name,
|
|
63
|
+
category: b.typeName ?? "",
|
|
64
|
+
values,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PragmaRuntime } from "../../shared/runtime.js";
|
|
2
|
+
import { listTokens } from "../operations/index.js";
|
|
3
|
+
import type { TokenListResolution } from "../types.js";
|
|
4
|
+
import tokenEmptyError from "./tokenEmptyError.js";
|
|
5
|
+
|
|
6
|
+
export default async function resolveTokenList(
|
|
7
|
+
rt: Pick<PragmaRuntime, "store">,
|
|
8
|
+
params: { category?: string },
|
|
9
|
+
): Promise<TokenListResolution> {
|
|
10
|
+
const items = await listTokens(rt.store, { category: params.category });
|
|
11
|
+
|
|
12
|
+
if (items.length === 0) {
|
|
13
|
+
throw tokenEmptyError(params.category);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return { params, items };
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { LookupContract, LookupResult } from "../../shared/contracts.js";
|
|
2
|
+
import lookupMany from "../../shared/lookupMany.js";
|
|
3
|
+
import type { PragmaRuntime } from "../../shared/runtime.js";
|
|
4
|
+
import type { TokenDetailed } from "../../shared/types.js";
|
|
5
|
+
import { lookupToken } from "../operations/index.js";
|
|
6
|
+
|
|
7
|
+
export default async function resolveTokenLookup(
|
|
8
|
+
store: Pick<PragmaRuntime, "store">["store"],
|
|
9
|
+
queries: readonly string[],
|
|
10
|
+
): Promise<LookupContract<TokenDetailed>> {
|
|
11
|
+
const result: LookupResult<TokenDetailed> = await lookupMany(
|
|
12
|
+
queries,
|
|
13
|
+
(query) => lookupToken(store, query),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
params: { names: queries },
|
|
18
|
+
result,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PragmaError } from "#error";
|
|
2
|
+
|
|
3
|
+
export default function tokenEmptyError(category?: string): PragmaError {
|
|
4
|
+
return PragmaError.emptyResults("token", {
|
|
5
|
+
filters: category ? { category } : undefined,
|
|
6
|
+
recovery: category
|
|
7
|
+
? {
|
|
8
|
+
message: "List all tokens without category filter.",
|
|
9
|
+
cli: "pragma token list",
|
|
10
|
+
mcp: { tool: "token_list" },
|
|
11
|
+
}
|
|
12
|
+
: {
|
|
13
|
+
message:
|
|
14
|
+
"Ensure design system packages are installed: bun add -D @canonical/ds-global",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
}
|