@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,91 @@
|
|
|
1
|
+
import type { CommandOutputResult } 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 lookupCommand from "./lookup.js";
|
|
7
|
+
|
|
8
|
+
let store: Store;
|
|
9
|
+
let cleanup: () => void;
|
|
10
|
+
|
|
11
|
+
beforeAll(async () => {
|
|
12
|
+
const result = await createTestStore({ ttl: DS_ALL_TTL });
|
|
13
|
+
store = result.store;
|
|
14
|
+
cleanup = result.cleanup;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterAll(() => cleanup());
|
|
18
|
+
|
|
19
|
+
function makeCtx(
|
|
20
|
+
overrides?: Partial<PragmaContext["globalFlags"]>,
|
|
21
|
+
): PragmaContext {
|
|
22
|
+
return {
|
|
23
|
+
cwd: "/tmp",
|
|
24
|
+
store,
|
|
25
|
+
config: { tier: undefined, channel: "normal" },
|
|
26
|
+
globalFlags: {
|
|
27
|
+
llm: false,
|
|
28
|
+
format: "text",
|
|
29
|
+
verbose: false,
|
|
30
|
+
...overrides,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("modifier lookup command", () => {
|
|
36
|
+
it("returns a family with values", async () => {
|
|
37
|
+
const ctx = makeCtx();
|
|
38
|
+
const cmd = lookupCommand(ctx);
|
|
39
|
+
const result = await cmd.execute({ names: ["density"] }, ctx);
|
|
40
|
+
expect(result.tag).toBe("output");
|
|
41
|
+
|
|
42
|
+
const output = result as CommandOutputResult;
|
|
43
|
+
const text = output.render.plain(output.value);
|
|
44
|
+
expect(text).toContain("density");
|
|
45
|
+
expect(text).toContain("default");
|
|
46
|
+
expect(text).toContain("compact");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("throws ENTITY_NOT_FOUND for unknown modifier", async () => {
|
|
50
|
+
const ctx = makeCtx();
|
|
51
|
+
const cmd = lookupCommand(ctx);
|
|
52
|
+
const result = await cmd.execute({ names: ["nonexistent"] }, ctx);
|
|
53
|
+
expect(result.tag).toBe("output");
|
|
54
|
+
if (result.tag !== "output") {
|
|
55
|
+
expect.fail("Expected output result");
|
|
56
|
+
}
|
|
57
|
+
expect(result.render.plain(result.value)).toContain("Errors:");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("renders LLM format with --llm", async () => {
|
|
61
|
+
const ctx = makeCtx({ llm: true });
|
|
62
|
+
const cmd = lookupCommand(ctx);
|
|
63
|
+
const result = await cmd.execute({ names: ["importance"] }, ctx);
|
|
64
|
+
const output = result as CommandOutputResult;
|
|
65
|
+
const text = output.render.plain(output.value);
|
|
66
|
+
expect(text).toContain("## importance");
|
|
67
|
+
expect(text).toContain("- default");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("renders JSON with --format json", async () => {
|
|
71
|
+
const ctx = makeCtx({ format: "json" });
|
|
72
|
+
const cmd = lookupCommand(ctx);
|
|
73
|
+
const result = await cmd.execute({ names: ["importance"] }, ctx);
|
|
74
|
+
const output = result as CommandOutputResult;
|
|
75
|
+
const text = output.render.plain(output.value);
|
|
76
|
+
const parsed = JSON.parse(text);
|
|
77
|
+
expect(parsed.name).toBe("importance");
|
|
78
|
+
expect(parsed.values).toContain("primary");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("renders multiple families together", async () => {
|
|
82
|
+
const ctx = makeCtx();
|
|
83
|
+
const cmd = lookupCommand(ctx);
|
|
84
|
+
const result = await cmd.execute({ names: ["importance", "density"] }, ctx);
|
|
85
|
+
expect(result.tag).toBe("output");
|
|
86
|
+
const output = result as CommandOutputResult;
|
|
87
|
+
const text = output.render.plain(output.value);
|
|
88
|
+
expect(text).toContain("importance");
|
|
89
|
+
expect(text).toContain("density");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wires the `pragma modifier lookup <name...>` CLI command.
|
|
3
|
+
*
|
|
4
|
+
* Retrieves a single modifier family by name and renders its values.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
type CommandDefinition,
|
|
9
|
+
createOutputResult,
|
|
10
|
+
} from "@canonical/cli-core";
|
|
11
|
+
import type { PragmaContext } from "../../shared/context.js";
|
|
12
|
+
import type { LookupResult } from "../../shared/contracts.js";
|
|
13
|
+
import { lookupFormatters } from "../formatters/index.js";
|
|
14
|
+
import type { lookupModifier } from "../operations/index.js";
|
|
15
|
+
import { resolveModifierLookup } from "../orchestration/index.js";
|
|
16
|
+
|
|
17
|
+
interface ModifierLookupOutput {
|
|
18
|
+
readonly result: LookupResult<Awaited<ReturnType<typeof lookupModifier>>>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default function buildLookupCommand(
|
|
22
|
+
ctx: PragmaContext,
|
|
23
|
+
): CommandDefinition {
|
|
24
|
+
return {
|
|
25
|
+
path: ["modifier", "lookup"],
|
|
26
|
+
description: "Look up a modifier family and its values",
|
|
27
|
+
parameters: [
|
|
28
|
+
{
|
|
29
|
+
name: "names",
|
|
30
|
+
description: "Modifier family names or IRIs",
|
|
31
|
+
type: "multiselect",
|
|
32
|
+
positional: true,
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
meta: {
|
|
37
|
+
examples: [
|
|
38
|
+
"pragma modifier lookup importance",
|
|
39
|
+
"pragma modifier lookup importance density",
|
|
40
|
+
"pragma modifier lookup importance --llm",
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
async execute(params: Record<string, unknown>) {
|
|
44
|
+
const names = normalizeNames(params.names, params.name);
|
|
45
|
+
const contract = await resolveModifierLookup(ctx.store, names);
|
|
46
|
+
|
|
47
|
+
return createOutputResult<ModifierLookupOutput>(
|
|
48
|
+
{ result: contract.result },
|
|
49
|
+
{ plain: renderModifierLookupOutput(ctx) },
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function normalizeNames(names: unknown, legacyName?: unknown): string[] {
|
|
56
|
+
if (Array.isArray(names)) {
|
|
57
|
+
return names.filter(
|
|
58
|
+
(name): name is string => typeof name === "string" && name.length > 0,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (typeof legacyName === "string" && legacyName.length > 0) {
|
|
62
|
+
return [legacyName];
|
|
63
|
+
}
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function renderModifierLookupOutput(
|
|
68
|
+
ctx: PragmaContext,
|
|
69
|
+
): (data: ModifierLookupOutput) => string {
|
|
70
|
+
return ({ result }) => {
|
|
71
|
+
const formatOne =
|
|
72
|
+
ctx.globalFlags.format === "json"
|
|
73
|
+
? lookupFormatters.json
|
|
74
|
+
: ctx.globalFlags.llm
|
|
75
|
+
? lookupFormatters.llm
|
|
76
|
+
: lookupFormatters.plain;
|
|
77
|
+
|
|
78
|
+
if (ctx.globalFlags.format === "json") {
|
|
79
|
+
if (result.results.length === 1 && result.errors.length === 0) {
|
|
80
|
+
const only = result.results[0];
|
|
81
|
+
return only
|
|
82
|
+
? lookupFormatters.json(only)
|
|
83
|
+
: JSON.stringify({ results: [], errors: result.errors }, null, 2);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return JSON.stringify(
|
|
87
|
+
{ results: result.results, errors: result.errors },
|
|
88
|
+
null,
|
|
89
|
+
2,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const parts = result.results.map((family) => formatOne(family));
|
|
94
|
+
if (result.errors.length > 0) {
|
|
95
|
+
parts.push(
|
|
96
|
+
[
|
|
97
|
+
"Errors:",
|
|
98
|
+
...result.errors.map((error) => `- ${error.query}: ${error.message}`),
|
|
99
|
+
].join("\n"),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return parts.join("\n\n");
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { URI } from "@canonical/ke";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import type { ModifierFamily } from "../../shared/types.js";
|
|
4
|
+
import formatters from "./list.js";
|
|
5
|
+
|
|
6
|
+
const FAMILIES: ModifierFamily[] = [
|
|
7
|
+
{
|
|
8
|
+
uri: "http://example.com/f1" as URI,
|
|
9
|
+
name: "importance",
|
|
10
|
+
values: ["default", "primary", "secondary"],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
uri: "http://example.com/f2" as URI,
|
|
14
|
+
name: "density",
|
|
15
|
+
values: ["default", "compact"],
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
describe("modifier list formatters", () => {
|
|
20
|
+
it("plain renders name with comma-separated values", () => {
|
|
21
|
+
const text = formatters.plain(FAMILIES);
|
|
22
|
+
expect(text).toContain("importance: default, primary, secondary");
|
|
23
|
+
expect(text).toContain("density: default, compact");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("llm renders markdown heading and bold names", () => {
|
|
27
|
+
const text = formatters.llm(FAMILIES);
|
|
28
|
+
expect(text).toContain("## Modifier Families");
|
|
29
|
+
expect(text).toContain("**importance**");
|
|
30
|
+
expect(text).toContain("**density**");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("json serializes the full array", () => {
|
|
34
|
+
const parsed = JSON.parse(formatters.json(FAMILIES));
|
|
35
|
+
expect(parsed).toHaveLength(2);
|
|
36
|
+
expect(parsed[0].name).toBe("importance");
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-mode formatter for `pragma modifier list` output.
|
|
3
|
+
*
|
|
4
|
+
* - **plain** — one line per family showing name and comma-separated values.
|
|
5
|
+
* - **llm** — condensed Markdown consumed by LLM agents and reused
|
|
6
|
+
* by the MCP adapter when `condensed: true`.
|
|
7
|
+
* - **json** — structured JSON array for programmatic consumption.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Formatters } from "../../shared/formatters.js";
|
|
11
|
+
import type { ModifierFamily } from "../../shared/types.js";
|
|
12
|
+
|
|
13
|
+
const formatters: Formatters<ModifierFamily[]> = {
|
|
14
|
+
plain: (families) => {
|
|
15
|
+
const lines: string[] = [];
|
|
16
|
+
for (const f of families) {
|
|
17
|
+
lines.push(`${f.name}: ${f.values.join(", ")}`);
|
|
18
|
+
}
|
|
19
|
+
return lines.join("\n");
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
llm: (families) => {
|
|
23
|
+
const lines: string[] = [];
|
|
24
|
+
lines.push("## Modifier Families");
|
|
25
|
+
lines.push("");
|
|
26
|
+
for (const f of families) {
|
|
27
|
+
lines.push(`- **${f.name}**: ${f.values.join(", ")}`);
|
|
28
|
+
}
|
|
29
|
+
return lines.join("\n");
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
json: (families) => JSON.stringify(families, null, 2),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default formatters;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { URI } from "@canonical/ke";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import type { ModifierFamily } from "../../shared/types.js";
|
|
4
|
+
import formatters from "./lookup.js";
|
|
5
|
+
|
|
6
|
+
const FAMILY: ModifierFamily = {
|
|
7
|
+
uri: "http://example.com/f1" as URI,
|
|
8
|
+
name: "importance",
|
|
9
|
+
values: ["default", "primary", "secondary"],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe("modifier lookup formatters", () => {
|
|
13
|
+
it("plain renders family name and indented values", () => {
|
|
14
|
+
const text = formatters.plain(FAMILY);
|
|
15
|
+
expect(text).toContain("importance");
|
|
16
|
+
expect(text).toContain("Values:");
|
|
17
|
+
expect(text).toContain(" default");
|
|
18
|
+
expect(text).toContain(" primary");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("llm renders markdown heading and value list", () => {
|
|
22
|
+
const text = formatters.llm(FAMILY);
|
|
23
|
+
expect(text).toContain("## importance");
|
|
24
|
+
expect(text).toContain("- default");
|
|
25
|
+
expect(text).toContain("- primary");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("json serializes the full family", () => {
|
|
29
|
+
const parsed = JSON.parse(formatters.json(FAMILY));
|
|
30
|
+
expect(parsed.name).toBe("importance");
|
|
31
|
+
expect(parsed.values).toEqual(["default", "primary", "secondary"]);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-mode formatter for `pragma modifier lookup` output.
|
|
3
|
+
*
|
|
4
|
+
* - **plain** — terminal text showing the family name and its values.
|
|
5
|
+
* - **llm** — condensed Markdown consumed by LLM agents and reused
|
|
6
|
+
* by the MCP adapter when `condensed: true`.
|
|
7
|
+
* - **json** — structured JSON for programmatic consumption.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { Formatters } from "../../shared/formatters.js";
|
|
11
|
+
import type { ModifierFamily } from "../../shared/types.js";
|
|
12
|
+
|
|
13
|
+
const formatters: Formatters<ModifierFamily> = {
|
|
14
|
+
plain: (family) => {
|
|
15
|
+
const lines: string[] = [];
|
|
16
|
+
lines.push(family.name);
|
|
17
|
+
lines.push("");
|
|
18
|
+
lines.push("Values:");
|
|
19
|
+
for (const v of family.values) {
|
|
20
|
+
lines.push(` ${v}`);
|
|
21
|
+
}
|
|
22
|
+
return lines.join("\n");
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
llm: (family) => {
|
|
26
|
+
const lines: string[] = [];
|
|
27
|
+
lines.push(`## ${family.name}`);
|
|
28
|
+
lines.push("");
|
|
29
|
+
for (const v of family.values) {
|
|
30
|
+
lines.push(`- ${v}`);
|
|
31
|
+
}
|
|
32
|
+
return lines.join("\n");
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
json: (family) => JSON.stringify(family, null, 2),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default formatters;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Modifier domain — CLI commands and operations.
|
|
3
|
+
*
|
|
4
|
+
* Commands: `pragma modifier list`, `pragma modifier lookup <name>`.
|
|
5
|
+
* Operations: {@link lookupModifier}, {@link listModifiers}.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { CommandDefinition } from "@canonical/cli-core";
|
|
9
|
+
import type { PragmaContext } from "../shared/context.js";
|
|
10
|
+
import { listCommand, lookupCommand } from "./commands/index.js";
|
|
11
|
+
|
|
12
|
+
export function commands(ctx: PragmaContext): CommandDefinition[] {
|
|
13
|
+
return [listCommand(ctx), lookupCommand(ctx)];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { specs as mcpSpecs } from "./mcp/index.js";
|
|
17
|
+
export { listModifiers, lookupModifier } from "./operations/index.js";
|
|
18
|
+
export {
|
|
19
|
+
modifierEmptyError,
|
|
20
|
+
resolveModifierList,
|
|
21
|
+
resolveModifierLookup,
|
|
22
|
+
} from "./orchestration/index.js";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool specs for the modifier domain.
|
|
3
|
+
*
|
|
4
|
+
* Declarative definitions — no MCP imports. The adapter layer
|
|
5
|
+
* converts these into registered MCP tools via `registerFromSpec()`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
9
|
+
import {
|
|
10
|
+
listFormatters as modifierListFmt,
|
|
11
|
+
lookupFormatters as modifierLookupFmt,
|
|
12
|
+
} from "../formatters/index.js";
|
|
13
|
+
import {
|
|
14
|
+
resolveModifierList,
|
|
15
|
+
resolveModifierLookup,
|
|
16
|
+
} from "../orchestration/index.js";
|
|
17
|
+
|
|
18
|
+
const specs: readonly ToolSpec[] = [
|
|
19
|
+
{
|
|
20
|
+
name: "modifier_list",
|
|
21
|
+
description: "List all modifier families with their values.",
|
|
22
|
+
params: {
|
|
23
|
+
condensed: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
description: "Token-optimized output",
|
|
26
|
+
optional: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
readOnly: true,
|
|
30
|
+
async execute(rt, { condensed }) {
|
|
31
|
+
const resolution = await resolveModifierList(rt);
|
|
32
|
+
|
|
33
|
+
if (condensed) {
|
|
34
|
+
const text = modifierListFmt.llm([...resolution.items]);
|
|
35
|
+
return {
|
|
36
|
+
condensed: true,
|
|
37
|
+
text,
|
|
38
|
+
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
data: resolution.items,
|
|
44
|
+
meta: { count: resolution.items.length },
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
name: "modifier_lookup",
|
|
51
|
+
description: "Get one or more modifier families and their values.",
|
|
52
|
+
params: {
|
|
53
|
+
names: {
|
|
54
|
+
type: "string[]",
|
|
55
|
+
description: "Modifier family names or IRIs to look up",
|
|
56
|
+
optional: false,
|
|
57
|
+
},
|
|
58
|
+
condensed: {
|
|
59
|
+
type: "boolean",
|
|
60
|
+
description: "Token-optimized output",
|
|
61
|
+
optional: true,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
readOnly: true,
|
|
65
|
+
async execute(rt, { names, condensed }) {
|
|
66
|
+
const contract = await resolveModifierLookup(rt.store, names as string[]);
|
|
67
|
+
const result = contract.result;
|
|
68
|
+
|
|
69
|
+
if (condensed) {
|
|
70
|
+
const textParts = result.results.map((family) =>
|
|
71
|
+
modifierLookupFmt.llm(family),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
if (result.errors.length > 0) {
|
|
75
|
+
textParts.push(
|
|
76
|
+
[
|
|
77
|
+
"### Errors",
|
|
78
|
+
...result.errors.map(
|
|
79
|
+
(error) => `- ${error.query}: ${error.message}`,
|
|
80
|
+
),
|
|
81
|
+
].join("\n"),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
condensed: true,
|
|
87
|
+
text: textParts.join("\n\n"),
|
|
88
|
+
tokens: `~${Math.ceil(textParts.join("\n\n").length / 4)}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { data: result, meta: { count: result.results.length } };
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
] as const;
|
|
96
|
+
|
|
97
|
+
export default specs;
|
|
@@ -0,0 +1,39 @@
|
|
|
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 listModifiers 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("listModifiers", () => {
|
|
18
|
+
it("returns all modifier families", async () => {
|
|
19
|
+
const result = await listModifiers(store);
|
|
20
|
+
const names = result.map((m) => m.name);
|
|
21
|
+
expect(names).toContain("importance");
|
|
22
|
+
expect(names).toContain("density");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("includes values for each family", async () => {
|
|
26
|
+
const result = await listModifiers(store);
|
|
27
|
+
const importance = result.find((m) => m.name === "importance");
|
|
28
|
+
expect(importance?.values).toContain("default");
|
|
29
|
+
expect(importance?.values).toContain("primary");
|
|
30
|
+
expect(importance?.values).toContain("secondary");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("returns sorted by name", async () => {
|
|
34
|
+
const result = await listModifiers(store);
|
|
35
|
+
const names = result.map((m) => m.name);
|
|
36
|
+
const sorted = [...names].sort();
|
|
37
|
+
expect(names).toEqual(sorted);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lists all modifier families with their allowed values, ordered by name.
|
|
3
|
+
*
|
|
4
|
+
* @param store - ke store to query
|
|
5
|
+
* @returns array of modifier families, empty when none exist
|
|
6
|
+
* @note Queries ke store
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Store, URI } from "@canonical/ke";
|
|
10
|
+
import { buildQuery } from "../../shared/buildQuery.js";
|
|
11
|
+
import { P } from "../../shared/prefixes.js";
|
|
12
|
+
import type { ModifierFamily } from "../../shared/types.js";
|
|
13
|
+
|
|
14
|
+
export default async function listModifiers(
|
|
15
|
+
store: Store,
|
|
16
|
+
): Promise<ModifierFamily[]> {
|
|
17
|
+
const result = await store.query(
|
|
18
|
+
buildQuery(`
|
|
19
|
+
SELECT ?family ?name (GROUP_CONCAT(DISTINCT ?valueName; separator="|") AS ?values)
|
|
20
|
+
WHERE {
|
|
21
|
+
?family a ${P.ds}ModifierFamily ;
|
|
22
|
+
${P.ds}name ?name .
|
|
23
|
+
OPTIONAL {
|
|
24
|
+
?mod a ${P.ds}Modifier ;
|
|
25
|
+
${P.ds}modifierFamily ?family ;
|
|
26
|
+
${P.ds}name ?valueName .
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
GROUP BY ?family ?name
|
|
30
|
+
ORDER BY ?name
|
|
31
|
+
`),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (result.type !== "select") return [];
|
|
35
|
+
|
|
36
|
+
return result.bindings.map((b) => ({
|
|
37
|
+
uri: (b.family ?? "") as URI,
|
|
38
|
+
name: b.name ?? "",
|
|
39
|
+
values: b.values ? b.values.split("|").filter(Boolean) : [],
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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 lookupModifier 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("lookupModifier", () => {
|
|
19
|
+
it("returns a single modifier family with values", async () => {
|
|
20
|
+
const result = await lookupModifier(store, "density");
|
|
21
|
+
expect(result.name).toBe("density");
|
|
22
|
+
expect(result.values).toContain("default");
|
|
23
|
+
expect(result.values).toContain("compact");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("throws PragmaError.notFound for unknown modifier", async () => {
|
|
27
|
+
await expect(lookupModifier(store, "nonexistent")).rejects.toThrow(
|
|
28
|
+
PragmaError,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
await lookupModifier(store, "nonexistent");
|
|
33
|
+
} catch (e) {
|
|
34
|
+
expect((e as PragmaError).code).toBe("ENTITY_NOT_FOUND");
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Look up a single modifier family by name, including its allowed values.
|
|
3
|
+
*
|
|
4
|
+
* @param store - ke store to query
|
|
5
|
+
* @param name - modifier family name (e.g. "importance")
|
|
6
|
+
* @returns the modifier family with its value list
|
|
7
|
+
* @throws PragmaError.notFound if the modifier family does not exist
|
|
8
|
+
* @note Queries ke store
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Store, URI } from "@canonical/ke";
|
|
12
|
+
import { escapeSparqlValue } from "@canonical/ke";
|
|
13
|
+
import { PragmaError } from "#error";
|
|
14
|
+
import { buildQuery } from "../../shared/buildQuery.js";
|
|
15
|
+
import { P } from "../../shared/prefixes.js";
|
|
16
|
+
import type { ModifierFamily } from "../../shared/types.js";
|
|
17
|
+
|
|
18
|
+
export default async function lookupModifier(
|
|
19
|
+
store: Store,
|
|
20
|
+
name: string,
|
|
21
|
+
): Promise<ModifierFamily> {
|
|
22
|
+
const escaped = escapeSparqlValue(name);
|
|
23
|
+
|
|
24
|
+
const result = await store.query(
|
|
25
|
+
buildQuery(`
|
|
26
|
+
SELECT ?family (GROUP_CONCAT(DISTINCT ?valueName; separator="|") AS ?values)
|
|
27
|
+
WHERE {
|
|
28
|
+
?family a ${P.ds}ModifierFamily ;
|
|
29
|
+
${P.ds}name ${escaped} .
|
|
30
|
+
OPTIONAL {
|
|
31
|
+
?mod a ${P.ds}Modifier ;
|
|
32
|
+
${P.ds}modifierFamily ?family ;
|
|
33
|
+
${P.ds}name ?valueName .
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
GROUP BY ?family
|
|
37
|
+
`),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (result.type !== "select" || result.bindings.length === 0) {
|
|
41
|
+
throw PragmaError.notFound("modifier", name, {
|
|
42
|
+
recovery: {
|
|
43
|
+
message: "List available modifiers.",
|
|
44
|
+
cli: "pragma modifier list",
|
|
45
|
+
mcp: { tool: "modifier_list" },
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Safe: length check above guarantees bindings[0] exists
|
|
51
|
+
const b = result.bindings[0] as (typeof result.bindings)[number];
|
|
52
|
+
return {
|
|
53
|
+
uri: (b.family ?? "") as URI,
|
|
54
|
+
name,
|
|
55
|
+
values: b.values ? b.values.split("|").filter(Boolean) : [],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PragmaError } from "#error";
|
|
2
|
+
|
|
3
|
+
export default function modifierEmptyError(): PragmaError {
|
|
4
|
+
return PragmaError.emptyResults("modifier", {
|
|
5
|
+
recovery: {
|
|
6
|
+
message:
|
|
7
|
+
"Ensure design system packages are installed: bun add -D @canonical/ds-global",
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
}
|