@canonical/pragma-cli 0.29.0 → 0.31.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 +128 -47
- package/dist/pragma +0 -0
- package/package.json +15 -13
- package/src/completions/constants.ts +7 -0
- package/src/completions/handleQuery.test.ts +32 -0
- package/src/completions/handleQuery.ts +20 -1
- package/src/completions/queryCompletions.test.ts +5 -0
- package/src/completions/queryCompletions.ts +17 -3
- package/src/completions/querySocket.test.ts +31 -0
- package/src/completions/querySocket.ts +36 -9
- package/src/config/defaultConfig.test.ts +33 -0
- package/src/config/defaultConfig.ts +59 -0
- package/src/config/defaults.json +17 -0
- package/src/config/findProjectConfigPath.test.ts +53 -0
- package/src/config/findProjectConfigPath.ts +36 -0
- package/src/config/index.ts +17 -2
- package/src/config/mergeConfigFileUpdate.ts +58 -0
- package/src/config/parseConfigValues.ts +217 -0
- package/src/config/readConfig.test.ts +104 -13
- package/src/config/readConfig.ts +12 -153
- package/src/config/readConfigLayers.test.ts +109 -0
- package/src/config/readConfigLayers.ts +118 -0
- package/src/config/resolveGlobalConfigPath.ts +13 -0
- package/src/config/resolveWriteConfigPath.test.ts +53 -0
- package/src/config/resolveWriteConfigPath.ts +31 -0
- package/src/config/types.ts +83 -1
- package/src/config/writeConfig.ts +25 -55
- package/src/constants.ts +3 -1
- package/src/domains/block/commands/list.ts +5 -90
- package/src/domains/block/commands/lookup.ts +8 -167
- package/src/domains/block/commands/sample.ts +2 -1
- package/src/domains/block/formatters/list.test.ts +3 -3
- package/src/domains/block/formatters/lookup.test.ts +5 -5
- package/src/domains/block/mcp/specs.ts +16 -196
- package/src/domains/block/orchestration/enrichBlocks.ts +6 -3
- package/src/domains/block/orchestration/resolveBlockLookup.ts +2 -1
- package/src/domains/block/stories.test.ts +28 -0
- package/src/domains/block/stories.ts +260 -0
- package/src/domains/config/commands/channel.test.ts +30 -3
- package/src/domains/config/commands/channel.ts +25 -8
- package/src/domains/config/commands/configScope.ts +46 -0
- package/src/domains/config/commands/framework.test.ts +32 -1
- package/src/domains/config/commands/framework.ts +26 -8
- package/src/domains/config/commands/show.ts +5 -45
- package/src/domains/config/commands/tier.test.ts +20 -2
- package/src/domains/config/commands/tier.ts +25 -8
- package/src/domains/config/commands/trace.test.ts +19 -2
- package/src/domains/config/commands/trace.ts +6 -3
- package/src/domains/config/formatters/channel.test.ts +20 -6
- package/src/domains/config/formatters/channel.ts +14 -11
- package/src/domains/config/formatters/framework.ts +14 -11
- package/src/domains/config/formatters/show.test.ts +27 -0
- package/src/domains/config/formatters/show.ts +27 -4
- package/src/domains/config/formatters/tier.test.ts +26 -10
- package/src/domains/config/formatters/tier.ts +19 -11
- package/src/domains/config/formatters/trace.ts +7 -7
- package/src/domains/config/mcp/specs.ts +33 -53
- package/src/domains/config/operations/show.test.ts +18 -0
- package/src/domains/config/operations/show.ts +7 -1
- package/src/domains/config/operations/types.ts +7 -0
- package/src/domains/config/operations/validateTier.test.ts +9 -0
- package/src/domains/config/operations/validateTier.ts +10 -2
- package/src/domains/config/stories.ts +42 -0
- package/src/domains/config/tasks/index.ts +1 -0
- package/src/domains/config/tasks/setChannel.ts +13 -28
- package/src/domains/config/tasks/setFramework.ts +11 -30
- package/src/domains/config/tasks/setTier.ts +10 -29
- package/src/domains/config/tasks/setTrace.ts +10 -28
- package/src/domains/config/tasks/writeConfigField.ts +41 -0
- package/src/domains/create/generatorPack/bundled.ts +49 -0
- package/src/domains/create/generatorPack/compileGeneratorPack.test.ts +159 -0
- package/src/domains/create/generatorPack/compileGeneratorPack.ts +312 -0
- package/src/domains/create/index.ts +13 -7
- package/src/domains/create/mcp/specs.ts +6 -161
- package/src/domains/create/renderGeneratorUi.test.ts +103 -0
- package/src/domains/create/renderGeneratorUi.ts +65 -0
- package/src/domains/doctor/formatters/doctor.test.ts +50 -2
- package/src/domains/doctor/formatters/doctor.ts +90 -38
- package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
- package/src/domains/doctor/operations/checks/checkMcpCommands.ts +133 -0
- package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
- package/src/domains/doctor/operations/checks/checkPackageRefs.ts +32 -26
- package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +1 -1
- package/src/domains/doctor/operations/checks/index.ts +1 -0
- package/src/domains/doctor/operations/checks.test.ts +160 -7
- package/src/domains/doctor/operations/runChecks.test.ts +15 -6
- package/src/domains/doctor/operations/runChecks.ts +2 -0
- package/src/domains/doctor/operations/types.ts +23 -1
- package/src/domains/graph/commands/inspect.test.ts +2 -2
- package/src/domains/graph/commands/query.test.ts +5 -3
- package/src/domains/graph/formatters/inspect.ts +7 -7
- package/src/domains/graph/formatters/query.test.ts +87 -0
- package/src/domains/graph/formatters/query.ts +42 -5
- package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
- package/src/domains/graph/helpers/resolveUri.ts +28 -21
- package/src/domains/graph/operations/inspectUri.test.ts +5 -5
- package/src/domains/graphql/commands/build.test.ts +5 -3
- package/src/domains/graphql/commands/build.ts +8 -16
- package/src/domains/graphql/commands/check.test.ts +5 -3
- package/src/domains/graphql/commands/check.ts +7 -13
- package/src/domains/graphql/commands/index.ts +1 -0
- package/src/domains/graphql/commands/serve.test.ts +46 -0
- package/src/domains/graphql/commands/serve.ts +141 -0
- package/src/domains/graphql/constants.ts +10 -0
- package/src/domains/graphql/helpers/gatherSources.test.ts +92 -0
- package/src/domains/graphql/helpers/gatherSources.ts +58 -0
- package/src/domains/graphql/helpers/index.ts +2 -0
- package/src/domains/graphql/helpers/parsePrefixes.test.ts +3 -3
- package/src/domains/graphql/helpers/parsePrefixes.ts +3 -3
- package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +9 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.ts +24 -3
- package/src/domains/graphql/helpers/routeGraphql.test.ts +43 -0
- package/src/domains/graphql/helpers/routeGraphql.ts +28 -0
- package/src/domains/graphql/index.ts +9 -6
- package/src/domains/graphql/operations/compileSchema.test.ts +23 -47
- package/src/domains/graphql/operations/compileSchema.ts +23 -25
- package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
- package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
- package/src/domains/graphql/operations/ensureSchemaArtifact.test.ts +167 -0
- package/src/domains/graphql/operations/ensureSchemaArtifact.ts +178 -0
- package/src/domains/graphql/operations/index.ts +10 -0
- package/src/domains/info/formatters/upgrade.test.ts +7 -4
- package/src/domains/info/formatters/upgrade.ts +3 -1
- package/src/domains/info/operations/collectEntityCounts.test.ts +156 -0
- package/src/domains/info/operations/collectEntityCounts.ts +123 -0
- package/src/domains/info/operations/collectInfo.test.ts +14 -3
- package/src/domains/info/operations/collectInfo.ts +12 -15
- package/src/domains/info/operations/index.ts +1 -0
- package/src/domains/info/types.ts +13 -0
- package/src/domains/llm/capabilities.test.ts +24 -4
- package/src/domains/llm/commands/capabilities.ts +12 -3
- package/src/domains/llm/commands/llm.ts +5 -1
- package/src/domains/llm/data/commandReference.ts +20 -11
- package/src/domains/llm/data/decisionTrees.ts +10 -5
- package/src/domains/llm/data/toolCatalog.ts +55 -18
- package/src/domains/llm/formatters/orientation.ts +5 -1
- package/src/domains/llm/llmCommand.test.ts +11 -3
- package/src/domains/llm/mcp/specs.ts +3 -4
- package/src/domains/llm/operations/collectContext.test.ts +64 -0
- package/src/domains/llm/operations/collectContext.ts +7 -17
- package/src/domains/modifier/commands/list.ts +5 -38
- package/src/domains/modifier/commands/lookup.ts +8 -79
- package/src/domains/modifier/commands/sample.ts +2 -1
- package/src/domains/modifier/mcp/specs.ts +15 -94
- package/src/domains/modifier/operations/lookup.ts +5 -3
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +2 -1
- package/src/domains/modifier/stories.test.ts +20 -0
- package/src/domains/modifier/stories.ts +86 -0
- package/src/domains/ontology/commands/list.test.ts +5 -3
- package/src/domains/ontology/commands/list.ts +5 -58
- package/src/domains/ontology/commands/show.test.ts +85 -9
- package/src/domains/ontology/commands/show.ts +6 -58
- package/src/domains/ontology/formatters/index.ts +1 -0
- package/src/domains/ontology/formatters/list.ts +37 -12
- package/src/domains/ontology/formatters/show.ts +361 -64
- package/src/domains/ontology/helpers/buildClassTree.ts +89 -0
- package/src/domains/ontology/helpers/completeClassNames.ts +43 -0
- package/src/domains/ontology/helpers/expandOntologyIris.ts +79 -0
- package/src/domains/ontology/helpers/index.ts +14 -0
- package/src/domains/ontology/helpers/queryClasses.ts +32 -16
- package/src/domains/ontology/helpers/queryProperties.ts +39 -6
- package/src/domains/ontology/helpers/queryTboxFacts.ts +160 -0
- package/src/domains/ontology/mcp/specs.ts +7 -84
- package/src/domains/ontology/operations/listOntologies.test.ts +80 -3
- package/src/domains/ontology/operations/listOntologies.ts +126 -30
- package/src/domains/ontology/operations/showOntology.test.ts +131 -12
- package/src/domains/ontology/operations/showOntology.ts +289 -7
- package/src/domains/ontology/operations/showOntologyRaw.test.ts +4 -2
- package/src/domains/ontology/stories.test.ts +36 -0
- package/src/domains/ontology/stories.ts +153 -0
- package/src/domains/refs/operations/updateRefs.ts +2 -38
- package/src/domains/setup/commands/index.ts +1 -0
- package/src/domains/setup/commands/setup.ts +70 -0
- package/src/domains/setup/commands/skills.test.ts +6 -2
- package/src/domains/setup/commands/skills.ts +6 -2
- package/src/domains/setup/helpers/runSetupTask.test.ts +148 -150
- package/src/domains/setup/helpers/runSetupTask.ts +62 -70
- package/src/domains/setup/index.ts +7 -3
- package/src/domains/setup/operations/setupLsp.test.ts +3 -2
- package/src/domains/setup/operations/setupLsp.ts +7 -2
- package/src/domains/setup/operations/setupMcp.test.ts +6 -1
- package/src/domains/shared/bootStore.bareCore.test.ts +63 -0
- package/src/domains/shared/bootStore.test.ts +82 -0
- package/src/domains/shared/bootStore.ts +57 -18
- package/src/domains/shared/compactUri.test.ts +11 -0
- package/src/domains/shared/compactUri.ts +10 -5
- package/src/domains/shared/context.ts +2 -2
- package/src/domains/shared/contracts.ts +11 -0
- package/src/domains/shared/createInteractivePromptSession.test.ts +439 -0
- package/src/domains/shared/createInteractivePromptSession.ts +236 -0
- package/src/domains/shared/emptyErrorRecovery.test.ts +23 -26
- package/src/domains/shared/extractLocalName.test.ts +3 -3
- package/src/domains/shared/formatters.ts +23 -2
- package/src/domains/shared/listTiers.ts +40 -0
- package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
- package/src/domains/shared/loaders/bundledLoader.ts +158 -12
- package/src/domains/shared/loaders/gitLoader.ts +1 -2
- package/src/domains/shared/loaders/index.ts +4 -1
- package/src/domains/shared/loaders/localLoader.ts +2 -4
- package/src/domains/shared/loaders/readPackageDir.test.ts +58 -0
- package/src/domains/shared/loaders/readPackageDir.ts +82 -9
- package/src/domains/shared/loaders/storyAssetsPlugin.test.ts +84 -0
- package/src/domains/shared/loaders/storyAssetsPlugin.ts +46 -0
- package/src/domains/shared/lookupMany.test.ts +135 -0
- package/src/domains/shared/lookupMany.ts +50 -2
- package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
- package/src/domains/shared/mergeAndParseRefs.ts +44 -0
- package/src/domains/shared/namespaces.ts +13 -5
- package/src/domains/shared/packages.ts +10 -17
- package/src/domains/shared/parseSampleCount.test.ts +47 -0
- package/src/domains/shared/parseSampleCount.ts +45 -0
- package/src/domains/shared/prefixes.test.ts +211 -0
- package/src/domains/shared/prefixes.ts +182 -15
- package/src/domains/shared/renderers.ts +5 -5
- package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
- package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
- package/src/domains/shared/resolveLookupExitCode.test.ts +48 -0
- package/src/domains/shared/resolveLookupExitCode.ts +42 -0
- package/src/domains/shared/runtime.ts +4 -63
- package/src/domains/shared/semanticPackage.test.ts +89 -0
- package/src/domains/shared/semanticPackage.ts +34 -3
- package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
- package/src/domains/shared/stories/compileLookupCommand.ts +102 -0
- package/src/domains/shared/stories/compileLookupTool.test.ts +105 -0
- package/src/domains/shared/stories/compileLookupTool.ts +96 -0
- package/src/domains/shared/stories/compileReadCommand.test.ts +121 -0
- package/src/domains/shared/stories/compileReadCommand.ts +48 -0
- package/src/domains/shared/stories/compileReadTool.test.ts +64 -0
- package/src/domains/shared/stories/compileReadTool.ts +38 -0
- package/src/domains/shared/stories/condense.test.ts +18 -0
- package/src/domains/shared/stories/condense.ts +15 -0
- package/src/domains/shared/stories/index.ts +20 -0
- package/src/domains/shared/stories/normalizeNames.test.ts +20 -0
- package/src/domains/shared/stories/normalizeNames.ts +22 -0
- package/src/domains/shared/stories/pack/applyPackFilters.test.ts +151 -0
- package/src/domains/shared/stories/pack/applyPackFilters.ts +111 -0
- package/src/domains/shared/stories/pack/applyPackSearch.test.ts +57 -0
- package/src/domains/shared/stories/pack/applyPackSearch.ts +41 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +81 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.ts +154 -0
- package/src/domains/shared/stories/pack/bundled/index.ts +23 -0
- package/src/domains/shared/stories/pack/bundled/standardPack.ts +164 -0
- package/src/domains/shared/stories/pack/bundled/tierPack.ts +50 -0
- package/src/domains/shared/stories/pack/collectPackStories.test.ts +406 -0
- package/src/domains/shared/stories/pack/collectPackStories.ts +158 -0
- package/src/domains/shared/stories/pack/compilePackCommands.ts +50 -0
- package/src/domains/shared/stories/pack/compilePackStories.test.ts +751 -0
- package/src/domains/shared/stories/pack/compilePackStories.ts +724 -0
- package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +55 -0
- package/src/domains/shared/stories/pack/index.ts +42 -0
- package/src/domains/shared/stories/pack/reservedVerbs.test.ts +213 -0
- package/src/domains/shared/stories/pack/reservedVerbs.ts +170 -0
- package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
- package/src/domains/shared/stories/pack/standardParity.test.ts +381 -0
- package/src/domains/shared/stories/pack/types.ts +224 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +742 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +859 -0
- package/src/domains/shared/stories/projectCliParameters.test.ts +59 -0
- package/src/domains/shared/stories/projectCliParameters.ts +57 -0
- package/src/domains/shared/stories/projectToolParams.test.ts +50 -0
- package/src/domains/shared/stories/projectToolParams.ts +32 -0
- package/src/domains/shared/stories/requirePragmaContext.test.ts +23 -0
- package/src/domains/shared/stories/requirePragmaContext.ts +23 -0
- package/src/domains/shared/stories/resolveLookupDetailed.test.ts +57 -0
- package/src/domains/shared/stories/resolveLookupDetailed.ts +27 -0
- package/src/domains/shared/stories/types.ts +179 -0
- package/src/domains/shared/suggestions/expandGlob.ts +1 -0
- package/src/domains/shared/suggestions/suggestNames.ts +43 -10
- package/src/domains/shared/types/index.ts +5 -9
- package/src/domains/shared/types/ontology.ts +119 -24
- package/src/domains/shared/types/standard.ts +9 -52
- package/src/domains/skill/commands/index.ts +3 -1
- package/src/domains/skill/commands/list.test.ts +6 -2
- package/src/domains/skill/commands/list.ts +5 -63
- package/src/domains/skill/commands/lookup.test.ts +118 -0
- package/src/domains/skill/commands/lookup.ts +14 -0
- package/src/domains/skill/formatters/index.ts +1 -0
- package/src/domains/skill/formatters/lookup.test.ts +46 -0
- package/src/domains/skill/formatters/lookup.ts +57 -0
- package/src/domains/skill/helpers/resolveSkillSources.ts +0 -1
- package/src/domains/skill/index.ts +7 -3
- package/src/domains/skill/mcp/specs.ts +10 -29
- package/src/domains/skill/operations/discover.test.ts +61 -30
- package/src/domains/skill/operations/discover.ts +28 -37
- package/src/domains/skill/operations/index.ts +2 -1
- package/src/domains/skill/operations/list.test.ts +15 -7
- package/src/domains/skill/operations/lookup.test.ts +91 -0
- package/src/domains/skill/operations/lookup.ts +70 -0
- package/src/domains/skill/stories.test.ts +43 -0
- package/src/domains/skill/stories.ts +103 -0
- package/src/domains/skill/types.ts +8 -0
- package/src/domains/token/commands/lookup.test.ts +8 -0
- package/src/domains/token/commands/lookup.ts +12 -0
- package/src/domains/token/commands/sample.ts +2 -1
- package/src/domains/token/featureFlag.ts +17 -0
- package/src/domains/token/index.ts +5 -0
- package/src/domains/token/mcp/specs.ts +18 -2
- package/src/domains/token/orchestration/resolveTokenLookup.ts +2 -1
- package/src/domains/trace/commands/resolveTraceLimit.test.ts +31 -0
- package/src/domains/trace/commands/show.ts +30 -4
- package/src/domains/trace/tracePlugin.test.ts +1 -1
- package/src/index.ts +1 -13
- package/src/mcp/registerResources.test.ts +382 -74
- package/src/mcp/registerResources.ts +5 -348
- package/src/mcp/resources/buildGraphIndex.ts +167 -0
- package/src/mcp/resources/buildResourceList.test.ts +97 -0
- package/src/mcp/resources/buildResourceList.ts +176 -0
- package/src/mcp/resources/classifyEntity.test.ts +40 -0
- package/src/mcp/resources/classifyEntity.ts +27 -0
- package/src/mcp/resources/constants.ts +105 -0
- package/src/mcp/resources/displayPredicates.ts +62 -0
- package/src/mcp/resources/pickFirstValue.test.ts +29 -0
- package/src/mcp/resources/pickFirstValue.ts +26 -0
- package/src/mcp/resources/pickPrimaryType.test.ts +41 -0
- package/src/mcp/resources/pickPrimaryType.ts +26 -0
- package/src/mcp/resources/rankUriCompletions.test.ts +52 -0
- package/src/mcp/resources/rankUriCompletions.ts +64 -0
- package/src/mcp/resources/readEntity.ts +169 -0
- package/src/mcp/resources/registerResources.ts +126 -0
- package/src/mcp/resources/types.ts +128 -0
- package/src/mcp/tools/index.ts +22 -5
- package/src/mcp/tools/registerTools.test.ts +167 -34
- package/src/mcp/types.ts +4 -0
- package/src/pipeline/collectCommands.test.ts +151 -1
- package/src/pipeline/collectCommands.ts +35 -13
- package/src/pipeline/createProgram.test.ts +5 -1
- package/src/pipeline/createProgram.ts +2 -2
- package/src/pipeline/firstRun.test.ts +80 -0
- package/src/pipeline/firstRun.ts +99 -0
- package/src/pipeline/parseGlobalFlags.test.ts +102 -1
- package/src/pipeline/parseGlobalFlags.ts +98 -9
- package/src/pipeline/resolveCommandKind.test.ts +12 -0
- package/src/pipeline/resolveCommandKind.ts +4 -0
- package/src/pipeline/rootHelp.test.ts +87 -0
- package/src/pipeline/rootHelp.ts +265 -0
- package/src/pipeline/runCli.orchestration.test.ts +28 -12
- package/src/pipeline/runCli.test.ts +17 -4
- package/src/pipeline/runCli.ts +202 -25
- package/src/testing/cli.ts +30 -2
- package/src/testing/createTestMcpClient.ts +4 -1
- package/src/testing/dsFixtures.ts +21 -4
- package/src/testing/index.ts +7 -0
- package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
- package/src/testing/integration/cli-user-stories.test.ts +63 -0
- package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
- package/src/testing/integration/edge-cases.test.ts +62 -50
- package/src/testing/integration/executor-execution.test.ts +103 -0
- package/src/testing/integration/executor-golden.test.ts +145 -0
- package/src/testing/integration/mcp-surface.test.ts +40 -15
- package/src/testing/integration/parity.test.ts +136 -82
- package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
- package/src/testing/setupXdgIsolation.ts +26 -0
- package/src/testing/standardParityFixtures.ts +35 -0
- package/src/testing/store.ts +4 -4
- package/src/testing/storyFixtures.ts +63 -0
- package/src/domains/create/commands/component.test.ts +0 -166
- package/src/domains/create/commands/component.ts +0 -123
- package/src/domains/create/commands/index.ts +0 -3
- package/src/domains/create/commands/package.test.ts +0 -35
- package/src/domains/create/commands/package.ts +0 -21
- package/src/domains/create/generators.ts +0 -8
- package/src/domains/standard/commands/categories.test.ts +0 -70
- package/src/domains/standard/commands/categories.ts +0 -48
- package/src/domains/standard/commands/index.ts +0 -6
- package/src/domains/standard/commands/list.test.ts +0 -105
- package/src/domains/standard/commands/list.ts +0 -90
- package/src/domains/standard/commands/lookup.test.ts +0 -135
- package/src/domains/standard/commands/lookup.ts +0 -99
- package/src/domains/standard/commands/sample.ts +0 -57
- package/src/domains/standard/formatters/categories.test.ts +0 -44
- package/src/domains/standard/formatters/categories.ts +0 -38
- package/src/domains/standard/formatters/index.ts +0 -10
- package/src/domains/standard/formatters/list.test.ts +0 -169
- package/src/domains/standard/formatters/list.ts +0 -184
- package/src/domains/standard/formatters/lookup.test.ts +0 -95
- package/src/domains/standard/formatters/lookup.ts +0 -101
- package/src/domains/standard/formatters/sample.ts +0 -15
- package/src/domains/standard/formatters/types.ts +0 -31
- package/src/domains/standard/index.ts +0 -40
- package/src/domains/standard/mcp/index.ts +0 -2
- package/src/domains/standard/mcp/specs.ts +0 -244
- package/src/domains/standard/operations/categories.test.ts +0 -61
- package/src/domains/standard/operations/categories.ts +0 -38
- package/src/domains/standard/operations/index.ts +0 -6
- package/src/domains/standard/operations/list.test.ts +0 -75
- package/src/domains/standard/operations/list.ts +0 -64
- package/src/domains/standard/operations/lookup.test.ts +0 -58
- package/src/domains/standard/operations/lookup.ts +0 -151
- package/src/domains/standard/operations/sample.ts +0 -35
- package/src/domains/standard/orchestration/buildStandardFilters.ts +0 -11
- package/src/domains/standard/orchestration/index.ts +0 -4
- package/src/domains/standard/orchestration/resolveStandardList.ts +0 -45
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +0 -32
- package/src/domains/standard/orchestration/standardEmptyError.test.ts +0 -33
- package/src/domains/standard/orchestration/standardEmptyError.ts +0 -29
- package/src/domains/standard/standardConfig.ts +0 -42
- package/src/domains/standard/types.ts +0 -15
- package/src/domains/tier/commands/index.ts +0 -3
- package/src/domains/tier/commands/list.test.ts +0 -67
- package/src/domains/tier/commands/list.ts +0 -59
- package/src/domains/tier/formatters/index.ts +0 -3
- package/src/domains/tier/formatters/list.test.ts +0 -33
- package/src/domains/tier/formatters/list.ts +0 -45
- package/src/domains/tier/index.ts +0 -17
- package/src/domains/tier/mcp/index.ts +0 -2
- package/src/domains/tier/mcp/specs.ts +0 -38
- package/src/domains/tier/operations/index.ts +0 -3
- package/src/domains/tier/operations/list.test.ts +0 -32
- package/src/domains/tier/operations/list.ts +0 -33
- package/src/pipeline/runInteractiveCommand.ts +0 -198
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Create domain — generator-pack-driven `create <noun>` commands.
|
|
3
|
+
*
|
|
4
|
+
* The create surface is compiled from bundled generator packs (a package's
|
|
5
|
+
* `generators` export), not hardcoded per generator. Every generator each
|
|
6
|
+
* bundled package ships is exposed as a `create <noun>` command and a
|
|
7
|
+
* `create_<noun>` MCP tool. See {@link ./generatorPack/compileGeneratorPack}.
|
|
8
|
+
*/
|
|
2
9
|
|
|
3
10
|
import type { CommandDefinition } from "@canonical/cli-core";
|
|
4
|
-
import
|
|
11
|
+
import bundledGeneratorPacks from "./generatorPack/bundled.js";
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
|
-
* Return all create command definitions
|
|
8
|
-
*
|
|
9
|
-
* @returns An array of CommandDefinitions for component and package generators.
|
|
14
|
+
* Return all create command definitions, compiled from the bundled
|
|
15
|
+
* generator packs.
|
|
10
16
|
*/
|
|
11
|
-
export function commands(): CommandDefinition[] {
|
|
12
|
-
return
|
|
17
|
+
export function commands(): readonly CommandDefinition[] {
|
|
18
|
+
return bundledGeneratorPacks().commands;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
export { specs as mcpSpecs } from "./mcp/index.js";
|
|
@@ -1,168 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP tool specs for create domain
|
|
2
|
+
* MCP tool specs for the create domain.
|
|
3
|
+
*
|
|
4
|
+
* Compiled from the bundled generator packs — one `create_<noun>` tool per
|
|
5
|
+
* generator noun — rather than hand-written per generator.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
|
-
import { executeGenerator } from "@canonical/cli-core";
|
|
6
|
-
import type { AnyGenerator } from "@canonical/summon-core";
|
|
7
|
-
import { generators as packageGenerators } from "@canonical/summon-package";
|
|
8
|
-
import { PragmaError } from "#error";
|
|
9
8
|
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
10
|
-
import
|
|
9
|
+
import bundledGeneratorPacks from "../generatorPack/bundled.js";
|
|
11
10
|
|
|
12
|
-
const specs: readonly ToolSpec[] =
|
|
13
|
-
{
|
|
14
|
-
name: "create_component",
|
|
15
|
-
description:
|
|
16
|
-
"Generate a design system component with TypeScript, tests, stories, and styles. Returns a JSON generation plan (dry-run).",
|
|
17
|
-
params: {
|
|
18
|
-
framework: {
|
|
19
|
-
type: "string",
|
|
20
|
-
description: "Component framework",
|
|
21
|
-
optional: false,
|
|
22
|
-
enum: ["react", "svelte", "lit"],
|
|
23
|
-
},
|
|
24
|
-
componentPath: {
|
|
25
|
-
type: "string",
|
|
26
|
-
description:
|
|
27
|
-
"Path for the component directory (e.g. 'src/components/Button')",
|
|
28
|
-
optional: false,
|
|
29
|
-
},
|
|
30
|
-
withStyles: {
|
|
31
|
-
type: "boolean",
|
|
32
|
-
description: "Include CSS styles (default: true)",
|
|
33
|
-
optional: true,
|
|
34
|
-
},
|
|
35
|
-
withStories: {
|
|
36
|
-
type: "boolean",
|
|
37
|
-
description: "Include Storybook stories (default: true)",
|
|
38
|
-
optional: true,
|
|
39
|
-
},
|
|
40
|
-
withSsrTests: {
|
|
41
|
-
type: "boolean",
|
|
42
|
-
description: "Include SSR tests (default: true)",
|
|
43
|
-
optional: true,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
readOnly: false,
|
|
47
|
-
destructive: false,
|
|
48
|
-
async execute(rt, params) {
|
|
49
|
-
const batchCtx = {
|
|
50
|
-
cwd: rt.cwd,
|
|
51
|
-
globalFlags: {
|
|
52
|
-
llm: false,
|
|
53
|
-
format: "json" as const,
|
|
54
|
-
verbose: false,
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const framework = params.framework as string;
|
|
59
|
-
const gen = COMPONENT_GENERATORS[framework];
|
|
60
|
-
if (!gen) {
|
|
61
|
-
throw PragmaError.invalidInput("framework", framework, {
|
|
62
|
-
validOptions: Object.keys(COMPONENT_GENERATORS),
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const genParams: Record<string, unknown> = {
|
|
67
|
-
componentPath: params.componentPath,
|
|
68
|
-
...(params.withStyles !== undefined && {
|
|
69
|
-
withStyles: params.withStyles,
|
|
70
|
-
}),
|
|
71
|
-
...(params.withStories !== undefined && {
|
|
72
|
-
withStories: params.withStories,
|
|
73
|
-
}),
|
|
74
|
-
...(params.withSsrTests !== undefined && {
|
|
75
|
-
withSsrTests: params.withSsrTests,
|
|
76
|
-
}),
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const result = await executeGenerator(gen, genParams, batchCtx);
|
|
80
|
-
if (result.tag === "output") {
|
|
81
|
-
const text = result.render.plain(result.value);
|
|
82
|
-
return { data: JSON.parse(text) };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
throw PragmaError.invalidInput(
|
|
86
|
-
"componentPath",
|
|
87
|
-
String(params.componentPath),
|
|
88
|
-
);
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: "create_package",
|
|
93
|
-
description:
|
|
94
|
-
"Generate a new npm package with proper configuration. Returns a JSON generation plan (dry-run).",
|
|
95
|
-
params: {
|
|
96
|
-
name: {
|
|
97
|
-
type: "string",
|
|
98
|
-
description: "Full package name (e.g. '@canonical/my-package')",
|
|
99
|
-
optional: false,
|
|
100
|
-
},
|
|
101
|
-
type: {
|
|
102
|
-
type: "string",
|
|
103
|
-
description: "Package type",
|
|
104
|
-
optional: false,
|
|
105
|
-
enum: ["tool-ts", "library", "css"],
|
|
106
|
-
},
|
|
107
|
-
description: {
|
|
108
|
-
type: "string",
|
|
109
|
-
description: "Package description",
|
|
110
|
-
optional: true,
|
|
111
|
-
},
|
|
112
|
-
withReact: {
|
|
113
|
-
type: "boolean",
|
|
114
|
-
description: "Add React dependencies (default: false)",
|
|
115
|
-
optional: true,
|
|
116
|
-
},
|
|
117
|
-
withStorybook: {
|
|
118
|
-
type: "boolean",
|
|
119
|
-
description: "Add Storybook config (default: false)",
|
|
120
|
-
optional: true,
|
|
121
|
-
},
|
|
122
|
-
withCli: {
|
|
123
|
-
type: "boolean",
|
|
124
|
-
description: "Add CLI entry point (default: false)",
|
|
125
|
-
optional: true,
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
readOnly: false,
|
|
129
|
-
destructive: false,
|
|
130
|
-
async execute(rt, params) {
|
|
131
|
-
const batchCtx = {
|
|
132
|
-
cwd: rt.cwd,
|
|
133
|
-
globalFlags: {
|
|
134
|
-
llm: false,
|
|
135
|
-
format: "json" as const,
|
|
136
|
-
verbose: false,
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const gen = packageGenerators.package as AnyGenerator | undefined;
|
|
141
|
-
if (!gen) throw PragmaError.internalError("Package generator not found");
|
|
142
|
-
|
|
143
|
-
const genParams: Record<string, unknown> = {
|
|
144
|
-
name: params.name,
|
|
145
|
-
type: params.type,
|
|
146
|
-
...(params.description !== undefined && {
|
|
147
|
-
description: params.description,
|
|
148
|
-
}),
|
|
149
|
-
...(params.withReact !== undefined && { withReact: params.withReact }),
|
|
150
|
-
...(params.withStorybook !== undefined && {
|
|
151
|
-
withStorybook: params.withStorybook,
|
|
152
|
-
}),
|
|
153
|
-
...(params.withCli !== undefined && { withCli: params.withCli }),
|
|
154
|
-
runInstall: false,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const result = await executeGenerator(gen, genParams, batchCtx);
|
|
158
|
-
if (result.tag === "output") {
|
|
159
|
-
const text = result.render.plain(result.value);
|
|
160
|
-
return { data: JSON.parse(text) };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
throw PragmaError.invalidInput("name", String(params.name));
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
];
|
|
11
|
+
const specs: readonly ToolSpec[] = bundledGeneratorPacks().specs;
|
|
167
12
|
|
|
168
13
|
export default specs;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { CommandContext } from "@canonical/cli-core";
|
|
2
|
+
import type { GeneratorDefinition } from "@canonical/summon-core";
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
const executeGeneratorMock = vi.fn(async () => ({
|
|
6
|
+
tag: "output" as const,
|
|
7
|
+
value: "",
|
|
8
|
+
render: { plain: () => "" },
|
|
9
|
+
}));
|
|
10
|
+
const renderAppMock = vi.fn(async () => {});
|
|
11
|
+
|
|
12
|
+
vi.mock("@canonical/cli-core", async (importOriginal) => {
|
|
13
|
+
const actual = await importOriginal<typeof import("@canonical/cli-core")>();
|
|
14
|
+
return {
|
|
15
|
+
...actual,
|
|
16
|
+
executeGenerator: executeGeneratorMock,
|
|
17
|
+
createGeneratorStamp: () => ({ generatorName: "g", version: "1" }),
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
vi.mock("@canonical/summon/ui", () => ({ renderApp: renderAppMock }));
|
|
22
|
+
|
|
23
|
+
const gen = {
|
|
24
|
+
meta: {},
|
|
25
|
+
prompts: [],
|
|
26
|
+
generate: () => ({}),
|
|
27
|
+
} as unknown as GeneratorDefinition;
|
|
28
|
+
|
|
29
|
+
function makeCtx(overrides: Partial<CommandContext["globalFlags"]> = {}) {
|
|
30
|
+
return {
|
|
31
|
+
cwd: "/tmp",
|
|
32
|
+
globalFlags: { llm: false, format: "text", verbose: false, ...overrides },
|
|
33
|
+
} as CommandContext;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function withTty<T>(
|
|
37
|
+
stdin: boolean,
|
|
38
|
+
stdout: boolean,
|
|
39
|
+
run: () => Promise<T>,
|
|
40
|
+
): Promise<T> {
|
|
41
|
+
const inPrev = process.stdin.isTTY;
|
|
42
|
+
const outPrev = process.stdout.isTTY;
|
|
43
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
44
|
+
value: stdin,
|
|
45
|
+
configurable: true,
|
|
46
|
+
});
|
|
47
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
48
|
+
value: stdout,
|
|
49
|
+
configurable: true,
|
|
50
|
+
});
|
|
51
|
+
try {
|
|
52
|
+
return await run();
|
|
53
|
+
} finally {
|
|
54
|
+
Object.defineProperty(process.stdin, "isTTY", {
|
|
55
|
+
value: inPrev,
|
|
56
|
+
configurable: true,
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(process.stdout, "isTTY", {
|
|
59
|
+
value: outPrev,
|
|
60
|
+
configurable: true,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
describe("renderGeneratorUi", () => {
|
|
66
|
+
afterEach(() => vi.clearAllMocks());
|
|
67
|
+
|
|
68
|
+
it("renders summon's Ink UI on an interactive terminal", async () => {
|
|
69
|
+
const { default: renderGeneratorUi } = await import(
|
|
70
|
+
"./renderGeneratorUi.js"
|
|
71
|
+
);
|
|
72
|
+
const result = await withTty(true, true, () =>
|
|
73
|
+
renderGeneratorUi(gen, {}, makeCtx()),
|
|
74
|
+
);
|
|
75
|
+
expect(renderAppMock).toHaveBeenCalledTimes(1);
|
|
76
|
+
expect(executeGeneratorMock).not.toHaveBeenCalled();
|
|
77
|
+
expect(result).toEqual({ tag: "exit", code: 0 });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("falls back to executeGenerator on a non-interactive terminal", async () => {
|
|
81
|
+
const { default: renderGeneratorUi } = await import(
|
|
82
|
+
"./renderGeneratorUi.js"
|
|
83
|
+
);
|
|
84
|
+
await withTty(false, false, () => renderGeneratorUi(gen, {}, makeCtx()));
|
|
85
|
+
expect(executeGeneratorMock).toHaveBeenCalledTimes(1);
|
|
86
|
+
expect(renderAppMock).not.toHaveBeenCalled();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it.each([
|
|
90
|
+
["--yes", { yes: true }],
|
|
91
|
+
["--dry-run", { dryRun: true }],
|
|
92
|
+
["--undo", { undo: true }],
|
|
93
|
+
["--llm", { llm: true }],
|
|
94
|
+
["--format json", { format: "json" }],
|
|
95
|
+
])("falls back to executeGenerator for %s even on a TTY", async (_label, params) => {
|
|
96
|
+
const { default: renderGeneratorUi } = await import(
|
|
97
|
+
"./renderGeneratorUi.js"
|
|
98
|
+
);
|
|
99
|
+
await withTty(true, true, () => renderGeneratorUi(gen, params, makeCtx()));
|
|
100
|
+
expect(executeGeneratorMock).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(renderAppMock).not.toHaveBeenCalled();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route a generator run to the right front-end.
|
|
3
|
+
*
|
|
4
|
+
* On an interactive terminal (no `--yes`, not a machine-output or preview-only
|
|
5
|
+
* mode), render summon's Ink `App` — the same colored prompt sequence,
|
|
6
|
+
* operations recap, and "Proceed?" confirmation the `summon` binary shows — so
|
|
7
|
+
* `pragma create`/`setup` match summon exactly without duplicating the UI. In
|
|
8
|
+
* every other case (piped/CI, `--yes`, `--llm`/`--format json`, `--dry-run`,
|
|
9
|
+
* `--undo`) fall back to the shared UI-free {@link executeGenerator}, which owns
|
|
10
|
+
* the batch, preview, and machine-readable paths.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type CommandContext,
|
|
15
|
+
type CommandResult,
|
|
16
|
+
createExitResult,
|
|
17
|
+
createGeneratorStamp,
|
|
18
|
+
executeGenerator,
|
|
19
|
+
} from "@canonical/cli-core";
|
|
20
|
+
import type { GeneratorDefinition } from "@canonical/summon-core";
|
|
21
|
+
|
|
22
|
+
/** Whether both stdin and stdout are attached to an interactive terminal. */
|
|
23
|
+
function isInteractiveTerminal(): boolean {
|
|
24
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Run a generator, preferring summon's rich Ink UI when interactive.
|
|
29
|
+
*
|
|
30
|
+
* @param gen - The generator to run.
|
|
31
|
+
* @param params - Parsed CLI params (flags + positional answers).
|
|
32
|
+
* @param ctx - The command context (global flags, cwd).
|
|
33
|
+
* @returns A CommandResult; the Ink path exits 0 after the UI closes.
|
|
34
|
+
* @note Impure — may take over the terminal via Ink and perform the run.
|
|
35
|
+
*/
|
|
36
|
+
export default async function renderGeneratorUi(
|
|
37
|
+
gen: GeneratorDefinition,
|
|
38
|
+
params: Record<string, unknown>,
|
|
39
|
+
ctx: CommandContext,
|
|
40
|
+
): Promise<CommandResult> {
|
|
41
|
+
const isLlm = params.llm === true || ctx.globalFlags.llm;
|
|
42
|
+
const isJson = params.format === "json" || ctx.globalFlags.format === "json";
|
|
43
|
+
const wantsBatch =
|
|
44
|
+
params.yes === true ||
|
|
45
|
+
params.dryRun === true ||
|
|
46
|
+
params.undo === true ||
|
|
47
|
+
isLlm ||
|
|
48
|
+
isJson;
|
|
49
|
+
|
|
50
|
+
// Machine/preview/batch modes and non-interactive terminals stay on the
|
|
51
|
+
// UI-free executor.
|
|
52
|
+
if (wantsBatch || !isInteractiveTerminal()) {
|
|
53
|
+
return executeGenerator(gen, params, ctx);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const { renderApp } = await import("@canonical/summon/ui");
|
|
57
|
+
const stampEnabled = params.generatedStamp !== false;
|
|
58
|
+
await renderApp({
|
|
59
|
+
generator: gen,
|
|
60
|
+
preview: params.preview !== false,
|
|
61
|
+
verbose: ctx.globalFlags.verbose === true,
|
|
62
|
+
stamp: stampEnabled ? createGeneratorStamp(gen) : undefined,
|
|
63
|
+
});
|
|
64
|
+
return createExitResult(0);
|
|
65
|
+
}
|
|
@@ -48,6 +48,26 @@ const mixed: DoctorData = {
|
|
|
48
48
|
skipped: 1,
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
+
const withItems: DoctorData = {
|
|
52
|
+
checks: [
|
|
53
|
+
{
|
|
54
|
+
name: "package refs",
|
|
55
|
+
status: "pass",
|
|
56
|
+
detail: "1 package resolved",
|
|
57
|
+
items: [
|
|
58
|
+
{
|
|
59
|
+
label: "@canonical/design-system",
|
|
60
|
+
status: "pass",
|
|
61
|
+
detail: "git v0.1.2 · 362 graphs, 3 skills",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
passed: 1,
|
|
67
|
+
failed: 0,
|
|
68
|
+
skipped: 0,
|
|
69
|
+
};
|
|
70
|
+
|
|
51
71
|
describe("doctor formatters", () => {
|
|
52
72
|
describe("plain", () => {
|
|
53
73
|
it("renders passing checks with ✓", () => {
|
|
@@ -74,6 +94,29 @@ describe("doctor formatters", () => {
|
|
|
74
94
|
const output = formatters.plain(allPass);
|
|
75
95
|
expect(output).not.toContain("Run ");
|
|
76
96
|
});
|
|
97
|
+
|
|
98
|
+
it("renders a summary tally", () => {
|
|
99
|
+
const output = formatters.plain(mixed);
|
|
100
|
+
expect(output).toContain("1 passed");
|
|
101
|
+
expect(output).toContain("2 failed");
|
|
102
|
+
expect(output).toContain("1 skipped");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("renders sub-items indented under a check", () => {
|
|
106
|
+
const output = formatters.plain(withItems);
|
|
107
|
+
expect(output).toContain("@canonical/design-system");
|
|
108
|
+
expect(output).toContain("git v0.1.2 · 362 graphs, 3 skills");
|
|
109
|
+
// sub-item lines are indented beneath the check headline
|
|
110
|
+
const lines = output.split("\n");
|
|
111
|
+
const sub = lines.find((l) => l.includes("@canonical/design-system"));
|
|
112
|
+
expect(sub?.startsWith(" ")).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("renders the remedy inline with a fix label", () => {
|
|
116
|
+
const output = formatters.plain(mixed);
|
|
117
|
+
expect(output).toContain("fix:");
|
|
118
|
+
expect(output).toContain("pragma config tier <tier>");
|
|
119
|
+
});
|
|
77
120
|
});
|
|
78
121
|
|
|
79
122
|
describe("llm", () => {
|
|
@@ -87,12 +130,17 @@ describe("doctor formatters", () => {
|
|
|
87
130
|
expect(output).toContain("- ✓ **Node version**: v24.1.0");
|
|
88
131
|
});
|
|
89
132
|
|
|
90
|
-
it("includes
|
|
133
|
+
it("includes inline fixes for failures", () => {
|
|
91
134
|
const output = formatters.llm(mixed);
|
|
92
|
-
expect(output).toContain("
|
|
135
|
+
expect(output).toContain("_fix:_");
|
|
93
136
|
expect(output).toContain("`pragma config tier <tier>`");
|
|
94
137
|
expect(output).toContain("`pragma setup completions`");
|
|
95
138
|
});
|
|
139
|
+
|
|
140
|
+
it("renders sub-items as nested bullets", () => {
|
|
141
|
+
const output = formatters.llm(withItems);
|
|
142
|
+
expect(output).toContain(" - ✓ @canonical/design-system");
|
|
143
|
+
});
|
|
96
144
|
});
|
|
97
145
|
|
|
98
146
|
describe("json", () => {
|
|
@@ -1,78 +1,130 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import type { Formatters } from "../../shared/formatters.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
CheckResult,
|
|
5
|
+
CheckStatus,
|
|
6
|
+
DoctorData,
|
|
7
|
+
} from "../operations/types.js";
|
|
4
8
|
|
|
5
|
-
/** Status icons for pass/fail/skip
|
|
6
|
-
const STATUS_ICONS = {
|
|
9
|
+
/** Status icons for pass/fail/skip results (checks and sub-items). */
|
|
10
|
+
const STATUS_ICONS: Record<CheckStatus, string> = {
|
|
7
11
|
pass: chalk.green("✓"),
|
|
8
12
|
fail: chalk.red("✗"),
|
|
9
13
|
skip: chalk.yellow("○"),
|
|
10
|
-
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const SUB_BULLET = chalk.dim("·");
|
|
17
|
+
const FIX_ARROW = chalk.cyan("↳");
|
|
18
|
+
const INDENT = " "; // aligns sub-lines under the check name
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
|
-
*
|
|
21
|
+
* Render one check as terminal lines: a headline row (icon, aligned name,
|
|
22
|
+
* detail), an optional indented breakdown of sub-items, and — for failures —
|
|
23
|
+
* an inline remedial instruction.
|
|
14
24
|
*
|
|
15
|
-
* @param check - The check result to
|
|
16
|
-
* @
|
|
25
|
+
* @param check - The check result to render.
|
|
26
|
+
* @param nameWidth - Width to pad check names to so details align in a column.
|
|
27
|
+
* @returns The lines for this check.
|
|
17
28
|
*/
|
|
18
|
-
function formatCheckPlain(check: CheckResult): string {
|
|
19
|
-
|
|
29
|
+
function formatCheckPlain(check: CheckResult, nameWidth: number): string[] {
|
|
30
|
+
const name = check.name.padEnd(nameWidth);
|
|
31
|
+
const label = check.status === "fail" ? chalk.red(name) : chalk.bold(name);
|
|
32
|
+
const lines = [
|
|
33
|
+
` ${STATUS_ICONS[check.status]} ${label} ${chalk.dim(check.detail)}`,
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
if (check.items && check.items.length > 0) {
|
|
37
|
+
const itemWidth = Math.max(...check.items.map((i) => i.label.length));
|
|
38
|
+
const anyStatus = check.items.some((i) => i.status !== undefined);
|
|
39
|
+
for (const item of check.items) {
|
|
40
|
+
const icon = anyStatus
|
|
41
|
+
? item.status
|
|
42
|
+
? `${STATUS_ICONS[item.status]} `
|
|
43
|
+
: " "
|
|
44
|
+
: "";
|
|
45
|
+
const itemLabel = item.detail ? item.label.padEnd(itemWidth) : item.label;
|
|
46
|
+
const detail = item.detail ? ` ${chalk.dim(item.detail)}` : "";
|
|
47
|
+
lines.push(`${INDENT}${SUB_BULLET} ${icon}${itemLabel}${detail}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (check.status === "fail" && check.remedy) {
|
|
52
|
+
lines.push(`${INDENT}${FIX_ARROW} ${chalk.cyan("fix:")} ${check.remedy}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return lines;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Render the pass/fail/skip tally, coloring non-zero fail/skip. */
|
|
59
|
+
function formatSummary(data: DoctorData): string {
|
|
60
|
+
const parts = [chalk.green(`${data.passed} passed`)];
|
|
61
|
+
parts.push(
|
|
62
|
+
data.failed > 0
|
|
63
|
+
? chalk.red(`${data.failed} failed`)
|
|
64
|
+
: chalk.dim(`${data.failed} failed`),
|
|
65
|
+
);
|
|
66
|
+
parts.push(
|
|
67
|
+
data.skipped > 0
|
|
68
|
+
? chalk.yellow(`${data.skipped} skipped`)
|
|
69
|
+
: chalk.dim(`${data.skipped} skipped`),
|
|
70
|
+
);
|
|
71
|
+
return ` ${parts.join(chalk.dim(" · "))}`;
|
|
20
72
|
}
|
|
21
73
|
|
|
22
74
|
/**
|
|
23
75
|
* Formatters for `pragma doctor` output.
|
|
24
76
|
*
|
|
25
|
-
* - **plain** renders
|
|
26
|
-
*
|
|
27
|
-
* - **
|
|
77
|
+
* - **plain** renders an aligned check list with indented sub-items and
|
|
78
|
+
* inline remedies, followed by a summary tally.
|
|
79
|
+
* - **llm** renders a Markdown list with nested sub-items and inline fixes.
|
|
80
|
+
* - **json** serializes the raw DoctorData (including `items`).
|
|
28
81
|
*/
|
|
29
82
|
const formatters: Formatters<DoctorData> = {
|
|
30
83
|
plain(data) {
|
|
31
|
-
const
|
|
84
|
+
const nameWidth = Math.max(...data.checks.map((c) => c.name.length), 0);
|
|
85
|
+
const lines: string[] = [chalk.bold("pragma doctor"), ""];
|
|
32
86
|
|
|
33
87
|
for (const check of data.checks) {
|
|
34
|
-
lines.push(formatCheckPlain(check));
|
|
88
|
+
lines.push(...formatCheckPlain(check, nameWidth));
|
|
35
89
|
}
|
|
36
90
|
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
}
|
|
91
|
+
lines.push("");
|
|
92
|
+
lines.push(formatSummary(data));
|
|
50
93
|
|
|
51
94
|
return lines.join("\n");
|
|
52
95
|
},
|
|
53
96
|
|
|
54
97
|
llm(data) {
|
|
55
|
-
const lines: string[] = [];
|
|
56
|
-
|
|
57
|
-
lines.push("## Doctor");
|
|
58
|
-
lines.push("");
|
|
98
|
+
const lines: string[] = ["## Doctor", ""];
|
|
59
99
|
|
|
60
100
|
for (const check of data.checks) {
|
|
61
101
|
const icon =
|
|
62
102
|
check.status === "pass" ? "✓" : check.status === "fail" ? "✗" : "○";
|
|
63
103
|
lines.push(`- ${icon} **${check.name}**: ${check.detail}`);
|
|
64
|
-
}
|
|
65
104
|
|
|
66
|
-
|
|
105
|
+
for (const item of check.items ?? []) {
|
|
106
|
+
const itemIcon =
|
|
107
|
+
item.status === "pass"
|
|
108
|
+
? "✓ "
|
|
109
|
+
: item.status === "fail"
|
|
110
|
+
? "✗ "
|
|
111
|
+
: item.status === "skip"
|
|
112
|
+
? "○ "
|
|
113
|
+
: "";
|
|
114
|
+
const detail = item.detail ? `: ${item.detail}` : "";
|
|
115
|
+
lines.push(` - ${itemIcon}${item.label}${detail}`);
|
|
116
|
+
}
|
|
67
117
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
lines.push("### Remedial");
|
|
71
|
-
for (const r of remedies) {
|
|
72
|
-
lines.push(`- \`${r.remedy}\``);
|
|
118
|
+
if (check.status === "fail" && check.remedy) {
|
|
119
|
+
lines.push(` - _fix:_ \`${check.remedy}\``);
|
|
73
120
|
}
|
|
74
121
|
}
|
|
75
122
|
|
|
123
|
+
lines.push("");
|
|
124
|
+
lines.push(
|
|
125
|
+
`_${data.passed} passed, ${data.failed} failed, ${data.skipped} skipped_`,
|
|
126
|
+
);
|
|
127
|
+
|
|
76
128
|
return lines.join("\n");
|
|
77
129
|
},
|
|
78
130
|
|
|
@@ -1,21 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readConfigLayers } from "#config";
|
|
2
2
|
import type { CheckContext, CheckResult } from "../types.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Check
|
|
5
|
+
* Check which config layer is active for the working directory.
|
|
6
|
+
*
|
|
7
|
+
* Passes when a project `pragma.config.json` is found up the tree, or —
|
|
8
|
+
* pragma is global-first — when only the global XDG config exists. Fails
|
|
9
|
+
* only when neither layer is configured.
|
|
6
10
|
*
|
|
7
11
|
* @param ctx - Check context with the working directory.
|
|
8
|
-
* @returns A CheckResult indicating pass or fail.
|
|
12
|
+
* @returns A CheckResult indicating pass or fail with the active layer.
|
|
9
13
|
* @note Impure
|
|
10
14
|
*/
|
|
11
15
|
export default async function checkConfigFile(
|
|
12
16
|
ctx: CheckContext,
|
|
13
17
|
): Promise<CheckResult> {
|
|
14
|
-
|
|
18
|
+
const layers = readConfigLayers(ctx.cwd);
|
|
19
|
+
|
|
20
|
+
if (layers.project.exists) {
|
|
21
|
+
return {
|
|
22
|
+
name: "pragma.config.json",
|
|
23
|
+
status: "pass",
|
|
24
|
+
detail: `found (${layers.project.path})`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (layers.global.exists) {
|
|
15
29
|
return {
|
|
16
30
|
name: "pragma.config.json",
|
|
17
31
|
status: "pass",
|
|
18
|
-
detail:
|
|
32
|
+
detail: `no project config — global config active (${layers.global.path})`,
|
|
19
33
|
};
|
|
20
34
|
}
|
|
21
35
|
|