@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,43 @@
|
|
|
1
|
+
import type { CommandContext } from "@canonical/cli-core";
|
|
2
|
+
import {
|
|
3
|
+
type CommandDefinition,
|
|
4
|
+
type CommandResult,
|
|
5
|
+
createOutputResult,
|
|
6
|
+
} from "@canonical/cli-core";
|
|
7
|
+
import { selectFormatter } from "../../shared/formatters.js";
|
|
8
|
+
import { doctorFormatters } from "../formatters/index.js";
|
|
9
|
+
import { runChecks } from "../operations/index.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `pragma doctor` command definition.
|
|
13
|
+
*
|
|
14
|
+
* Runs all environment health checks (Node version, pragma installation,
|
|
15
|
+
* config file, ke store, shell completions, MCP, skills)
|
|
16
|
+
* and sets exit code 1 when any check fails.
|
|
17
|
+
*
|
|
18
|
+
* @note Impure
|
|
19
|
+
*/
|
|
20
|
+
const doctorCommand: CommandDefinition = {
|
|
21
|
+
path: ["doctor"],
|
|
22
|
+
description: "Check environment health",
|
|
23
|
+
parameters: [],
|
|
24
|
+
meta: {
|
|
25
|
+
examples: ["pragma doctor"],
|
|
26
|
+
},
|
|
27
|
+
execute: async (
|
|
28
|
+
_params: Record<string, unknown>,
|
|
29
|
+
ctx: CommandContext,
|
|
30
|
+
): Promise<CommandResult> => {
|
|
31
|
+
const data = await runChecks({ cwd: ctx.cwd });
|
|
32
|
+
|
|
33
|
+
if (data.failed > 0) {
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return createOutputResult(data, {
|
|
38
|
+
plain: selectFormatter(ctx, doctorFormatters),
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default doctorCommand;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import type { DoctorData } from "../operations/types.js";
|
|
3
|
+
import formatters from "./doctor.js";
|
|
4
|
+
|
|
5
|
+
const allPass: DoctorData = {
|
|
6
|
+
checks: [
|
|
7
|
+
{ name: "Node version", status: "pass", detail: "v24.1.0" },
|
|
8
|
+
{
|
|
9
|
+
name: "pragma version",
|
|
10
|
+
status: "pass",
|
|
11
|
+
detail: "v0.18.0 (installed via bun, global)",
|
|
12
|
+
},
|
|
13
|
+
{ name: "pragma.config.json", status: "pass", detail: "found" },
|
|
14
|
+
{
|
|
15
|
+
name: "ke store",
|
|
16
|
+
status: "pass",
|
|
17
|
+
detail: "12,847 triples in 180ms",
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
passed: 4,
|
|
21
|
+
failed: 0,
|
|
22
|
+
skipped: 0,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const mixed: DoctorData = {
|
|
26
|
+
checks: [
|
|
27
|
+
{ name: "Node version", status: "pass", detail: "v24.1.0" },
|
|
28
|
+
{
|
|
29
|
+
name: "pragma.config.json",
|
|
30
|
+
status: "fail",
|
|
31
|
+
detail: "not found",
|
|
32
|
+
remedy: "pragma config tier <tier>",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "skills",
|
|
36
|
+
status: "skip",
|
|
37
|
+
detail: "no harnesses detected",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "Shell completions",
|
|
41
|
+
status: "fail",
|
|
42
|
+
detail: "not installed",
|
|
43
|
+
remedy: "pragma setup completions",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
passed: 1,
|
|
47
|
+
failed: 2,
|
|
48
|
+
skipped: 1,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
describe("doctor formatters", () => {
|
|
52
|
+
describe("plain", () => {
|
|
53
|
+
it("renders passing checks with ✓", () => {
|
|
54
|
+
const output = formatters.plain(allPass);
|
|
55
|
+
expect(output).toContain("✓");
|
|
56
|
+
expect(output).toContain("Node version");
|
|
57
|
+
expect(output).toContain("v24.1.0");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("renders failing checks with ✗ and remedies at the bottom", () => {
|
|
61
|
+
const output = formatters.plain(mixed);
|
|
62
|
+
expect(output).toContain("✗");
|
|
63
|
+
expect(output).toContain("pragma config tier <tier>");
|
|
64
|
+
expect(output).toContain("pragma setup completions");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("renders skipped checks with ○", () => {
|
|
68
|
+
const output = formatters.plain(mixed);
|
|
69
|
+
expect(output).toContain("○");
|
|
70
|
+
expect(output).toContain("skills");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("does not render remedies section when all pass", () => {
|
|
74
|
+
const output = formatters.plain(allPass);
|
|
75
|
+
expect(output).not.toContain("Run ");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("llm", () => {
|
|
80
|
+
it("renders Markdown with ## Doctor heading", () => {
|
|
81
|
+
const output = formatters.llm(allPass);
|
|
82
|
+
expect(output).toContain("## Doctor");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("renders checks as bullet list", () => {
|
|
86
|
+
const output = formatters.llm(allPass);
|
|
87
|
+
expect(output).toContain("- ✓ **Node version**: v24.1.0");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("includes remedial section for failures", () => {
|
|
91
|
+
const output = formatters.llm(mixed);
|
|
92
|
+
expect(output).toContain("### Remedial");
|
|
93
|
+
expect(output).toContain("`pragma config tier <tier>`");
|
|
94
|
+
expect(output).toContain("`pragma setup completions`");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("json", () => {
|
|
99
|
+
it("returns valid JSON matching the data shape", () => {
|
|
100
|
+
const output = formatters.json(allPass);
|
|
101
|
+
const parsed = JSON.parse(output);
|
|
102
|
+
expect(parsed.passed).toBe(4);
|
|
103
|
+
expect(parsed.failed).toBe(0);
|
|
104
|
+
expect(parsed.checks).toHaveLength(4);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("includes remedy fields for failed checks", () => {
|
|
108
|
+
const output = formatters.json(mixed);
|
|
109
|
+
const parsed = JSON.parse(output);
|
|
110
|
+
const failedChecks = parsed.checks.filter(
|
|
111
|
+
(c: { status: string }) => c.status === "fail",
|
|
112
|
+
);
|
|
113
|
+
expect(failedChecks).toHaveLength(2);
|
|
114
|
+
expect(failedChecks[0].remedy).toBeDefined();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { Formatters } from "../../shared/formatters.js";
|
|
3
|
+
import type { CheckResult, DoctorData } from "../operations/types.js";
|
|
4
|
+
|
|
5
|
+
/** Status icons for pass/fail/skip check results. */
|
|
6
|
+
const STATUS_ICONS = {
|
|
7
|
+
pass: chalk.green("✓"),
|
|
8
|
+
fail: chalk.red("✗"),
|
|
9
|
+
skip: chalk.yellow("○"),
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Format a single check result as a styled terminal line.
|
|
14
|
+
*
|
|
15
|
+
* @param check - The check result to format.
|
|
16
|
+
* @returns A single-line string with status icon, name, and detail.
|
|
17
|
+
*/
|
|
18
|
+
function formatCheckPlain(check: CheckResult): string {
|
|
19
|
+
return `${STATUS_ICONS[check.status]} ${check.name} ${chalk.dim(check.detail)}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Formatters for `pragma doctor` output.
|
|
24
|
+
*
|
|
25
|
+
* - **plain** renders a check list with chalk icons and remedial commands.
|
|
26
|
+
* - **llm** renders a markdown list with remedial section.
|
|
27
|
+
* - **json** serializes the raw DoctorData.
|
|
28
|
+
*/
|
|
29
|
+
const formatters: Formatters<DoctorData> = {
|
|
30
|
+
plain(data) {
|
|
31
|
+
const lines: string[] = [];
|
|
32
|
+
|
|
33
|
+
for (const check of data.checks) {
|
|
34
|
+
lines.push(formatCheckPlain(check));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const remedies = data.checks.filter(
|
|
38
|
+
(c): c is CheckResult & { remedy: string } =>
|
|
39
|
+
c.status === "fail" && c.remedy !== undefined,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (remedies.length > 0) {
|
|
43
|
+
lines.push("");
|
|
44
|
+
for (const r of remedies) {
|
|
45
|
+
lines.push(
|
|
46
|
+
`Run ${chalk.cyan(`\`${r.remedy}\``)} to fix ${chalk.dim(r.name)}.`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return lines.join("\n");
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
llm(data) {
|
|
55
|
+
const lines: string[] = [];
|
|
56
|
+
|
|
57
|
+
lines.push("## Doctor");
|
|
58
|
+
lines.push("");
|
|
59
|
+
|
|
60
|
+
for (const check of data.checks) {
|
|
61
|
+
const icon =
|
|
62
|
+
check.status === "pass" ? "✓" : check.status === "fail" ? "✗" : "○";
|
|
63
|
+
lines.push(`- ${icon} **${check.name}**: ${check.detail}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const remedies = data.checks.filter((c) => c.status === "fail" && c.remedy);
|
|
67
|
+
|
|
68
|
+
if (remedies.length > 0) {
|
|
69
|
+
lines.push("");
|
|
70
|
+
lines.push("### Remedial");
|
|
71
|
+
for (const r of remedies) {
|
|
72
|
+
lines.push(`- \`${r.remedy}\``);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return lines.join("\n");
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
json(data) {
|
|
80
|
+
return JSON.stringify(data, null, 2);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export default formatters;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @module Doctor domain -- environment health checks via `pragma doctor`. */
|
|
2
|
+
export { doctorCommand } from "./commands/index.js";
|
|
3
|
+
export { specs as mcpSpecs } from "./mcp/index.js";
|
|
4
|
+
export type {
|
|
5
|
+
CheckContext,
|
|
6
|
+
CheckResult,
|
|
7
|
+
DoctorData,
|
|
8
|
+
} from "./operations/index.js";
|
|
9
|
+
export { runChecks } from "./operations/index.js";
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool specs for doctor domain — doctor, info.
|
|
3
|
+
*
|
|
4
|
+
* The info tool is cross-domain: it uses operations and formatters from
|
|
5
|
+
* the info domain, plus VERSION from #constants.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { VERSION } from "#constants";
|
|
9
|
+
import { detectInstallSource } from "#package-manager";
|
|
10
|
+
import { renderInfoLlm } from "../../info/formatters/index.js";
|
|
11
|
+
import { collectStoreSummary } from "../../info/operations/index.js";
|
|
12
|
+
import type { InfoData } from "../../info/types.js";
|
|
13
|
+
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
14
|
+
import { doctorFormatters } from "../formatters/index.js";
|
|
15
|
+
import { runChecks } from "../operations/index.js";
|
|
16
|
+
|
|
17
|
+
const specs: readonly ToolSpec[] = [
|
|
18
|
+
{
|
|
19
|
+
name: "doctor",
|
|
20
|
+
description:
|
|
21
|
+
"Run health checks on the pragma environment. Validates config, store, completions, skills, and more.",
|
|
22
|
+
params: {
|
|
23
|
+
condensed: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
description: "Token-optimized output",
|
|
26
|
+
optional: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
readOnly: true,
|
|
30
|
+
async execute(rt, params) {
|
|
31
|
+
const result = await runChecks({ cwd: rt.cwd });
|
|
32
|
+
|
|
33
|
+
if (params.condensed) {
|
|
34
|
+
const text = doctorFormatters.llm(result);
|
|
35
|
+
return {
|
|
36
|
+
condensed: true,
|
|
37
|
+
text,
|
|
38
|
+
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return { data: result };
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "info",
|
|
47
|
+
description: "Show pragma version, configuration, and store summary.",
|
|
48
|
+
params: {
|
|
49
|
+
condensed: {
|
|
50
|
+
type: "boolean",
|
|
51
|
+
description: "Token-optimized output",
|
|
52
|
+
optional: true,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
readOnly: true,
|
|
56
|
+
async execute(rt, params) {
|
|
57
|
+
const storeSummary = await collectStoreSummary(rt.store);
|
|
58
|
+
const install = detectInstallSource();
|
|
59
|
+
|
|
60
|
+
const data: InfoData = {
|
|
61
|
+
version: VERSION,
|
|
62
|
+
pm: install.packageManager,
|
|
63
|
+
installSource: install.label,
|
|
64
|
+
configPath: "pragma.config.json",
|
|
65
|
+
tier: rt.config.tier,
|
|
66
|
+
tierChain: [],
|
|
67
|
+
channel: rt.config.channel,
|
|
68
|
+
channelReleases: [],
|
|
69
|
+
update: undefined,
|
|
70
|
+
updateSkipped: true,
|
|
71
|
+
store: storeSummary,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (params.condensed) {
|
|
75
|
+
const text = renderInfoLlm(data);
|
|
76
|
+
return {
|
|
77
|
+
condensed: true,
|
|
78
|
+
text,
|
|
79
|
+
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { data };
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
export default specs;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { configExists } from "#config";
|
|
2
|
+
import type { CheckContext, CheckResult } from "../types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check that `pragma.config.json` exists in the working directory.
|
|
6
|
+
*
|
|
7
|
+
* @param ctx - Check context with the working directory.
|
|
8
|
+
* @returns A CheckResult indicating pass or fail.
|
|
9
|
+
* @note Impure
|
|
10
|
+
*/
|
|
11
|
+
export default async function checkConfigFile(
|
|
12
|
+
ctx: CheckContext,
|
|
13
|
+
): Promise<CheckResult> {
|
|
14
|
+
if (configExists(ctx.cwd)) {
|
|
15
|
+
return {
|
|
16
|
+
name: "pragma.config.json",
|
|
17
|
+
status: "pass",
|
|
18
|
+
detail: "found",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
name: "pragma.config.json",
|
|
24
|
+
status: "fail",
|
|
25
|
+
detail: "not found",
|
|
26
|
+
remedy: "pragma config tier <tier>",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { collectStoreSummary } from "../../../info/operations/index.js";
|
|
2
|
+
import { bootStore } from "../../../shared/bootStore.js";
|
|
3
|
+
import type { CheckContext, CheckResult } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check that the ke store boots successfully, reporting triple count
|
|
7
|
+
* and boot time.
|
|
8
|
+
*
|
|
9
|
+
* @param ctx - Check context with the working directory.
|
|
10
|
+
* @returns A CheckResult indicating pass (with triple count) or fail.
|
|
11
|
+
* @note Impure
|
|
12
|
+
*/
|
|
13
|
+
export default async function checkKeStore(
|
|
14
|
+
ctx: CheckContext,
|
|
15
|
+
): Promise<CheckResult> {
|
|
16
|
+
const start = performance.now();
|
|
17
|
+
let store: Awaited<ReturnType<typeof bootStore>> | undefined;
|
|
18
|
+
try {
|
|
19
|
+
store = await bootStore({ cwd: ctx.cwd });
|
|
20
|
+
const summary = await collectStoreSummary(store);
|
|
21
|
+
const elapsed = Math.round(performance.now() - start);
|
|
22
|
+
return {
|
|
23
|
+
name: "ke store",
|
|
24
|
+
status: "pass",
|
|
25
|
+
detail: `${summary.tripleCount.toLocaleString()} triples in ${elapsed}ms`,
|
|
26
|
+
};
|
|
27
|
+
} catch {
|
|
28
|
+
return {
|
|
29
|
+
name: "ke store",
|
|
30
|
+
status: "fail",
|
|
31
|
+
detail: "failed to boot",
|
|
32
|
+
remedy:
|
|
33
|
+
"Ensure design system packages are installed: bun add -D @canonical/ds-global @canonical/code-standards",
|
|
34
|
+
};
|
|
35
|
+
} finally {
|
|
36
|
+
store?.dispose();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { DetectedHarness } from "@canonical/harnesses";
|
|
2
|
+
import { detectHarnesses, readMcpConfig } from "@canonical/harnesses";
|
|
3
|
+
import { runTask } from "@canonical/task";
|
|
4
|
+
import type { CheckContext, CheckResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check that at least one AI harness has pragma configured as an MCP server.
|
|
8
|
+
*
|
|
9
|
+
* @param ctx - Check context with the working directory.
|
|
10
|
+
* @returns A CheckResult listing configured harnesses, or fail with remedy.
|
|
11
|
+
* @note Impure
|
|
12
|
+
*/
|
|
13
|
+
export default async function checkMcpConfigured(
|
|
14
|
+
ctx: CheckContext,
|
|
15
|
+
): Promise<CheckResult> {
|
|
16
|
+
let detected: DetectedHarness[];
|
|
17
|
+
try {
|
|
18
|
+
detected = await runTask(detectHarnesses(ctx.cwd));
|
|
19
|
+
} catch {
|
|
20
|
+
return {
|
|
21
|
+
name: "MCP configured",
|
|
22
|
+
status: "fail",
|
|
23
|
+
detail: "harness detection failed",
|
|
24
|
+
remedy: "pragma setup mcp",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (detected.length === 0) {
|
|
29
|
+
return {
|
|
30
|
+
name: "MCP configured",
|
|
31
|
+
status: "fail",
|
|
32
|
+
detail: "no AI harnesses detected",
|
|
33
|
+
remedy: "pragma setup mcp",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const configured: string[] = [];
|
|
38
|
+
for (const d of detected) {
|
|
39
|
+
if (!d.configExists) continue;
|
|
40
|
+
try {
|
|
41
|
+
const servers = await runTask(readMcpConfig(d.harness, ctx.cwd));
|
|
42
|
+
if ("pragma" in servers) {
|
|
43
|
+
configured.push(d.harness.name);
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// Config unreadable — skip
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (configured.length > 0) {
|
|
51
|
+
return {
|
|
52
|
+
name: "MCP configured",
|
|
53
|
+
status: "pass",
|
|
54
|
+
detail: configured.join(", "),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const names = detected.map((d) => d.harness.name).join(", ");
|
|
59
|
+
return {
|
|
60
|
+
name: "MCP configured",
|
|
61
|
+
status: "fail",
|
|
62
|
+
detail: `detected ${names} but pragma not configured`,
|
|
63
|
+
remedy: "pragma setup mcp",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CheckResult } from "../types.js";
|
|
2
|
+
|
|
3
|
+
const MIN_NODE_MAJOR = 20;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check that the Node.js major version is at least {@link MIN_NODE_MAJOR}.
|
|
7
|
+
*
|
|
8
|
+
* @returns A CheckResult with the current version and pass/fail status.
|
|
9
|
+
* @note Impure
|
|
10
|
+
*/
|
|
11
|
+
export default async function checkNodeVersion(): Promise<CheckResult> {
|
|
12
|
+
const version = process.versions.node;
|
|
13
|
+
const major = Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
14
|
+
|
|
15
|
+
if (major >= MIN_NODE_MAJOR) {
|
|
16
|
+
return { name: "Node version", status: "pass", detail: `v${version}` };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
name: "Node version",
|
|
21
|
+
status: "fail",
|
|
22
|
+
detail: `v${version} (requires >= ${MIN_NODE_MAJOR})`,
|
|
23
|
+
remedy: `Install Node.js >= ${MIN_NODE_MAJOR}`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { VERSION } from "#constants";
|
|
2
|
+
import { detectInstallSource } from "#package-manager";
|
|
3
|
+
import type { CheckResult } from "../types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Report pragma version, install method, and global/local status.
|
|
7
|
+
* Always passes -- this is purely informational.
|
|
8
|
+
*
|
|
9
|
+
* @returns A CheckResult with version and install details.
|
|
10
|
+
* @note Impure
|
|
11
|
+
*/
|
|
12
|
+
export default async function checkPragmaVersion(): Promise<CheckResult> {
|
|
13
|
+
const install = detectInstallSource();
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
name: "pragma version",
|
|
17
|
+
status: "pass",
|
|
18
|
+
detail: `v${VERSION} (installed via ${install.label})`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import type { CheckResult } from "../types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check whether "pragma" appears in any of the user's shell RC files
|
|
8
|
+
* (`.bashrc`, `.zshrc`, `config.fish`), indicating completions are installed.
|
|
9
|
+
*
|
|
10
|
+
* @returns A CheckResult indicating pass (installed) or fail with remedy.
|
|
11
|
+
* @note Impure
|
|
12
|
+
*/
|
|
13
|
+
export default async function checkShellCompletions(): Promise<CheckResult> {
|
|
14
|
+
const home = homedir();
|
|
15
|
+
const rcFiles = [
|
|
16
|
+
join(home, ".bashrc"),
|
|
17
|
+
join(home, ".zshrc"),
|
|
18
|
+
join(home, ".config", "fish", "config.fish"),
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
for (const rcFile of rcFiles) {
|
|
22
|
+
try {
|
|
23
|
+
const content = readFileSync(rcFile, "utf-8");
|
|
24
|
+
if (content.includes("pragma")) {
|
|
25
|
+
return {
|
|
26
|
+
name: "Shell completions",
|
|
27
|
+
status: "pass",
|
|
28
|
+
detail: "installed",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// File doesn't exist — continue
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
name: "Shell completions",
|
|
38
|
+
status: "fail",
|
|
39
|
+
detail: "not installed",
|
|
40
|
+
remedy: "pragma setup completions",
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import type { DetectedHarness } from "@canonical/harnesses";
|
|
3
|
+
import { detectHarnesses } from "@canonical/harnesses";
|
|
4
|
+
import { runTask } from "@canonical/task";
|
|
5
|
+
import type { CheckContext, CheckResult } from "../types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Check that skill directories exist for each detected AI harness.
|
|
9
|
+
* Skipped when no harnesses are detected.
|
|
10
|
+
*
|
|
11
|
+
* @param ctx - Check context with the working directory.
|
|
12
|
+
* @returns A CheckResult indicating pass, fail, or skip.
|
|
13
|
+
* @note Impure
|
|
14
|
+
*/
|
|
15
|
+
export default async function checkSkillsSymlinked(
|
|
16
|
+
ctx: CheckContext,
|
|
17
|
+
): Promise<CheckResult> {
|
|
18
|
+
let detected: DetectedHarness[];
|
|
19
|
+
try {
|
|
20
|
+
detected = await runTask(detectHarnesses(ctx.cwd));
|
|
21
|
+
} catch {
|
|
22
|
+
return {
|
|
23
|
+
name: "Skills symlinked",
|
|
24
|
+
status: "fail",
|
|
25
|
+
detail: "harness detection failed",
|
|
26
|
+
remedy: "pragma setup skills",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (detected.length === 0) {
|
|
31
|
+
return {
|
|
32
|
+
name: "Skills symlinked",
|
|
33
|
+
status: "skip",
|
|
34
|
+
detail: "no AI harnesses detected",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const linked: string[] = [];
|
|
39
|
+
const missing: string[] = [];
|
|
40
|
+
|
|
41
|
+
for (const d of detected) {
|
|
42
|
+
const skillsPath = d.harness.skillsPath(ctx.cwd);
|
|
43
|
+
if (existsSync(skillsPath)) {
|
|
44
|
+
linked.push(d.harness.name);
|
|
45
|
+
} else {
|
|
46
|
+
missing.push(d.harness.name);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (missing.length === 0) {
|
|
51
|
+
return {
|
|
52
|
+
name: "Skills symlinked",
|
|
53
|
+
status: "pass",
|
|
54
|
+
detail: linked.join(", "),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
name: "Skills symlinked",
|
|
60
|
+
status: "fail",
|
|
61
|
+
detail: `missing for ${missing.join(", ")}`,
|
|
62
|
+
remedy: "pragma setup skills",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** @module Individual environment health checks invoked by runChecks. */
|
|
2
|
+
export { default as checkConfigFile } from "./checkConfigFile.js";
|
|
3
|
+
export { default as checkKeStore } from "./checkKeStore.js";
|
|
4
|
+
export { default as checkMcpConfigured } from "./checkMcpConfigured.js";
|
|
5
|
+
export { default as checkNodeVersion } from "./checkNodeVersion.js";
|
|
6
|
+
export { default as checkPragmaVersion } from "./checkPragmaVersion.js";
|
|
7
|
+
export { default as checkShellCompletions } from "./checkShellCompletions.js";
|
|
8
|
+
export { default as checkSkillsSymlinked } from "./checkSkillsSymlinked.js";
|