@canonical/pragma-cli 0.27.1-experimental.0 → 0.30.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 +67 -15
- package/dist/pragma +0 -0
- package/package.json +16 -17
- 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 +215 -0
- package/src/config/readConfig.test.ts +104 -13
- package/src/config/readConfig.ts +12 -117
- package/src/config/readConfigLayers.test.ts +107 -0
- package/src/config/readConfigLayers.ts +115 -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 +88 -2
- package/src/config/writeConfig.ts +25 -43
- package/src/constants.ts +12 -1
- package/src/domains/block/commands/index.ts +2 -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 +55 -0
- package/src/domains/block/formatters/index.ts +2 -1
- package/src/domains/block/formatters/sample.ts +21 -0
- package/src/domains/block/index.ts +3 -3
- package/src/domains/block/mcp/specs.ts +36 -168
- package/src/domains/block/operations/index.ts +2 -1
- package/src/domains/block/operations/lookup.ts +9 -0
- package/src/domains/block/operations/sample.ts +41 -0
- package/src/domains/block/orchestration/blockEmptyError.test.ts +26 -0
- package/src/domains/block/orchestration/resolveBlockLookup.ts +11 -3
- package/src/domains/block/stories.test.ts +28 -0
- package/src/domains/block/stories.ts +254 -0
- package/src/domains/config/commands/channel.test.ts +14 -3
- package/src/domains/config/commands/channel.ts +11 -7
- package/src/domains/config/commands/configScope.ts +46 -0
- package/src/domains/config/commands/framework.test.ts +105 -0
- package/src/domains/config/commands/framework.ts +91 -0
- package/src/domains/config/commands/index.ts +2 -0
- package/src/domains/config/commands/show.ts +5 -45
- package/src/domains/config/commands/tier.test.ts +13 -2
- package/src/domains/config/commands/tier.ts +11 -7
- package/src/domains/config/commands/trace.test.ts +165 -0
- package/src/domains/config/commands/trace.ts +83 -0
- 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 +37 -0
- package/src/domains/config/formatters/index.ts +2 -0
- 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 +28 -0
- package/src/domains/config/index.ts +15 -2
- package/src/domains/config/mcp/specs.ts +33 -53
- package/src/domains/config/operations/index.ts +1 -0
- 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/validateFramework.ts +24 -0
- package/src/domains/config/stories.ts +42 -0
- package/src/domains/config/tasks/index.ts +3 -0
- package/src/domains/config/tasks/setChannel.ts +13 -22
- package/src/domains/config/tasks/setFramework.ts +21 -0
- package/src/domains/config/tasks/setTier.ts +10 -23
- package/src/domains/config/tasks/setTrace.ts +20 -0
- package/src/domains/config/tasks/writeConfigField.ts +41 -0
- package/src/domains/create/commands/component.ts +5 -5
- package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
- package/src/domains/doctor/operations/checks/checkKeStore.ts +5 -5
- package/src/domains/doctor/operations/checks/checkMcpCommands.ts +130 -0
- package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
- package/src/domains/doctor/operations/checks/checkPackageRefs.ts +30 -48
- 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 +162 -8
- package/src/domains/doctor/operations/runChecks.test.ts +85 -4
- package/src/domains/doctor/operations/runChecks.ts +50 -12
- package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
- package/src/domains/graph/helpers/resolveUri.ts +28 -21
- package/src/domains/graphql/commands/build.test.ts +196 -0
- package/src/domains/graphql/commands/build.ts +117 -0
- package/src/domains/graphql/commands/check.test.ts +141 -0
- package/src/domains/graphql/commands/check.ts +81 -0
- package/src/domains/graphql/commands/index.ts +5 -0
- package/src/domains/graphql/commands/serve.test.ts +40 -0
- package/src/domains/graphql/commands/serve.ts +131 -0
- package/src/domains/graphql/constants.ts +10 -0
- package/src/domains/graphql/formatters/index.ts +3 -0
- package/src/domains/graphql/formatters/report.ts +78 -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 +6 -0
- package/src/domains/graphql/helpers/parsePrefixes.test.ts +44 -0
- package/src/domains/graphql/helpers/parsePrefixes.ts +38 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +56 -0
- package/src/domains/graphql/helpers/resolveSourceFiles.ts +45 -0
- 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 +24 -0
- package/src/domains/graphql/operations/compileSchema.test.ts +95 -0
- package/src/domains/graphql/operations/compileSchema.ts +107 -0
- package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
- package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
- package/src/domains/graphql/operations/index.ts +12 -0
- package/src/domains/graphql/types.ts +29 -0
- package/src/domains/info/operations/collectInfo.test.ts +16 -5
- package/src/domains/info/operations/collectInfo.ts +16 -19
- package/src/domains/llm/capabilities.test.ts +91 -0
- package/src/domains/llm/commands/capabilities.ts +28 -0
- package/src/domains/llm/commands/index.ts +1 -0
- package/src/domains/llm/data/commandReference.ts +90 -18
- package/src/domains/llm/data/decisionTrees.ts +15 -13
- package/src/domains/llm/data/index.ts +2 -0
- package/src/domains/llm/data/toolCatalog.ts +190 -0
- package/src/domains/llm/formatters/capabilities.ts +50 -0
- package/src/domains/llm/formatters/index.ts +1 -0
- package/src/domains/llm/index.ts +3 -2
- package/src/domains/llm/mcp/index.ts +1 -1
- package/src/domains/llm/mcp/specs.ts +59 -52
- package/src/domains/llm/types.ts +40 -0
- package/src/domains/modifier/commands/index.ts +2 -1
- 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 +53 -0
- package/src/domains/modifier/formatters/index.ts +2 -1
- package/src/domains/modifier/formatters/sample.ts +15 -0
- package/src/domains/modifier/index.ts +7 -3
- package/src/domains/modifier/mcp/specs.ts +38 -70
- package/src/domains/modifier/operations/index.ts +2 -1
- package/src/domains/modifier/operations/lookup.ts +9 -0
- package/src/domains/modifier/operations/sample.ts +32 -0
- package/src/domains/modifier/orchestration/modifierEmptyError.test.ts +26 -0
- package/src/domains/modifier/orchestration/modifierEmptyError.ts +7 -2
- package/src/domains/modifier/orchestration/resolveModifierLookup.ts +15 -2
- package/src/domains/modifier/stories.test.ts +20 -0
- package/src/domains/modifier/stories.ts +77 -0
- package/src/domains/ontology/commands/list.ts +5 -58
- package/src/domains/ontology/commands/show.ts +6 -58
- package/src/domains/ontology/formatters/show.ts +7 -1
- package/src/domains/ontology/mcp/specs.ts +7 -84
- package/src/domains/ontology/stories.test.ts +36 -0
- package/src/domains/ontology/stories.ts +108 -0
- package/src/domains/refs/operations/index.ts +1 -1
- package/src/domains/refs/operations/paths.ts +29 -1
- package/src/domains/refs/operations/updateRefs.test.ts +6 -3
- package/src/domains/refs/operations/updateRefs.ts +2 -36
- 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/operations/setupMcp.test.ts +6 -1
- package/src/domains/shared/bootStore.ts +92 -50
- 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 +12 -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 +109 -0
- package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
- package/src/domains/shared/loaders/bundledLoader.ts +206 -0
- package/src/domains/shared/loaders/gitLoader.ts +31 -0
- package/src/domains/shared/loaders/index.ts +9 -0
- package/src/domains/shared/loaders/localLoader.ts +87 -0
- package/src/domains/shared/loaders/readPackageDir.ts +147 -0
- 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 +120 -0
- package/src/domains/shared/lookupMany.ts +43 -3
- package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
- package/src/domains/shared/mergeAndParseRefs.ts +44 -0
- package/src/domains/shared/packages.ts +14 -120
- package/src/domains/shared/pickRandom.ts +22 -0
- package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
- package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
- package/src/domains/shared/runtime.ts +7 -63
- package/src/domains/shared/sampleFormatters.ts +47 -0
- package/src/domains/shared/semanticPackage.ts +112 -0
- package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
- package/src/domains/shared/stories/compileLookupCommand.ts +100 -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 +102 -0
- package/src/domains/shared/stories/pack/applyPackFilters.ts +76 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +51 -0
- package/src/domains/shared/stories/pack/buildLookupQuery.ts +80 -0
- package/src/domains/shared/stories/pack/collectPackStories.test.ts +108 -0
- package/src/domains/shared/stories/pack/collectPackStories.ts +76 -0
- package/src/domains/shared/stories/pack/compilePackCommands.ts +40 -0
- package/src/domains/shared/stories/pack/compilePackStories.test.ts +146 -0
- package/src/domains/shared/stories/pack/compilePackStories.ts +253 -0
- package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +43 -0
- package/src/domains/shared/stories/pack/index.ts +28 -0
- package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
- package/src/domains/shared/stories/pack/standardParity.test.ts +308 -0
- package/src/domains/shared/stories/pack/types.ts +104 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +240 -0
- package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +408 -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 +171 -0
- package/src/domains/shared/suggestions/detectCrossDomain.test.ts +43 -0
- package/src/domains/shared/suggestions/detectCrossDomain.ts +116 -0
- package/src/domains/shared/suggestions/expandGlob.test.ts +92 -0
- package/src/domains/shared/suggestions/expandGlob.ts +52 -0
- package/src/domains/shared/suggestions/expandLookupQueries.ts +57 -0
- package/src/domains/shared/suggestions/index.ts +7 -0
- package/src/domains/shared/suggestions/listDomainNames.ts +61 -0
- package/src/domains/shared/suggestions/suggestNames.test.ts +70 -0
- package/src/domains/shared/suggestions/suggestNames.ts +130 -0
- package/src/domains/shared/types/index.ts +1 -0
- package/src/domains/shared/types/runtime.ts +4 -1
- package/src/domains/shared/types/sample.ts +17 -0
- 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 +48 -16
- 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/standard/commands/index.ts +2 -1
- package/src/domains/standard/commands/list.ts +5 -84
- package/src/domains/standard/commands/lookup.ts +8 -93
- package/src/domains/standard/commands/sample.ts +57 -0
- package/src/domains/standard/formatters/index.ts +2 -1
- package/src/domains/standard/formatters/sample.ts +15 -0
- package/src/domains/standard/index.ts +8 -1
- package/src/domains/standard/mcp/specs.ts +44 -152
- package/src/domains/standard/operations/index.ts +2 -1
- package/src/domains/standard/operations/lookup.ts +9 -0
- package/src/domains/standard/operations/sample.ts +35 -0
- package/src/domains/standard/orchestration/resolveStandardLookup.ts +15 -2
- package/src/domains/standard/orchestration/standardEmptyError.test.ts +33 -0
- package/src/domains/standard/orchestration/standardEmptyError.ts +16 -6
- package/src/domains/standard/stories.test.ts +24 -0
- package/src/domains/standard/stories.ts +151 -0
- package/src/domains/tier/commands/list.ts +5 -55
- package/src/domains/tier/mcp/specs.ts +5 -31
- package/src/domains/tier/stories.test.ts +22 -0
- package/src/domains/tier/stories.ts +52 -0
- package/src/domains/token/commands/index.ts +2 -1
- package/src/domains/token/commands/sample.ts +53 -0
- package/src/domains/token/formatters/index.ts +2 -1
- package/src/domains/token/formatters/sample.ts +16 -0
- package/src/domains/token/index.ts +8 -1
- package/src/domains/token/mcp/specs.ts +52 -2
- package/src/domains/token/operations/index.ts +2 -1
- package/src/domains/token/operations/lookup.ts +9 -0
- package/src/domains/token/operations/sample.ts +32 -0
- package/src/domains/token/orchestration/resolveTokenLookup.ts +15 -2
- package/src/domains/token/orchestration/tokenEmptyError.test.ts +33 -0
- package/src/domains/token/orchestration/tokenEmptyError.ts +5 -2
- package/src/domains/trace/commands/clear.ts +71 -0
- package/src/domains/trace/commands/index.ts +5 -0
- package/src/domains/trace/commands/sessions.ts +32 -0
- package/src/domains/trace/commands/show.ts +145 -0
- package/src/domains/trace/formatters/index.ts +9 -0
- package/src/domains/trace/formatters/sessions.ts +80 -0
- package/src/domains/trace/formatters/show.ts +122 -0
- package/src/domains/trace/index.ts +17 -0
- package/src/domains/trace/operations/index.ts +8 -0
- package/src/domains/trace/operations/listSessions.test.ts +55 -0
- package/src/domains/trace/operations/listSessions.ts +52 -0
- package/src/domains/trace/operations/readTraceLog.test.ts +100 -0
- package/src/domains/trace/operations/readTraceLog.ts +104 -0
- package/src/domains/trace/tracePlugin.test.ts +171 -0
- package/src/domains/trace/tracePlugin.ts +159 -0
- package/src/domains/trace/types.ts +65 -0
- package/src/error/PragmaError.ts +15 -2
- package/src/error/types.ts +15 -1
- package/src/mcp/error/serializeErrorPayload.ts +7 -0
- package/src/mcp/error/types.ts +8 -0
- package/src/mcp/registerResources.test.ts +405 -75
- package/src/mcp/registerResources.ts +5 -299
- 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 +9 -0
- package/src/mcp/tools/registerTools.test.ts +84 -12
- package/src/mcp/types.ts +4 -0
- package/src/mcp/utils/wrapTool.test.ts +1 -0
- package/src/pipeline/collectCommands.ts +15 -2
- package/src/pipeline/renderError.ts +15 -0
- package/src/pipeline/resolveCommandKind.ts +8 -1
- package/src/pipeline/runCli.ts +51 -6
- package/src/testing/createTestMcpClient.ts +5 -1
- package/src/testing/graphqlFixtures.ts +72 -0
- package/src/testing/index.ts +17 -0
- package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
- package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
- package/src/testing/integration/executor-execution.test.ts +101 -0
- package/src/testing/integration/executor-golden.test.ts +145 -0
- package/src/testing/integration/mcp-surface.test.ts +11 -5
- package/src/testing/integration/parity.test.ts +17 -12
- package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
- package/src/testing/setupXdgIsolation.ts +15 -0
- package/src/testing/standardParityFixtures.ts +92 -0
- package/src/testing/storyFixtures.ts +63 -0
- package/src/pipeline/runInteractiveCommand.ts +0 -198
|
@@ -2,36 +2,52 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import formatters from "./tier.js";
|
|
3
3
|
|
|
4
4
|
describe("tierFormatters.set", () => {
|
|
5
|
-
const data = {
|
|
5
|
+
const data = {
|
|
6
|
+
field: "tier",
|
|
7
|
+
value: "apps/lxd",
|
|
8
|
+
path: "/repo/pragma.config.json",
|
|
9
|
+
};
|
|
6
10
|
|
|
7
|
-
it("plain renders set message", () => {
|
|
8
|
-
expect(formatters.set.plain(data)).toBe(
|
|
11
|
+
it("plain renders set message with the written path", () => {
|
|
12
|
+
expect(formatters.set.plain(data)).toBe(
|
|
13
|
+
'Set tier to "apps/lxd".\nWrote /repo/pragma.config.json',
|
|
14
|
+
);
|
|
9
15
|
});
|
|
10
16
|
|
|
11
|
-
it("llm renders set message", () => {
|
|
12
|
-
expect(formatters.set.llm(data)).toBe(
|
|
17
|
+
it("llm renders set message with the written path", () => {
|
|
18
|
+
expect(formatters.set.llm(data)).toBe(
|
|
19
|
+
'Set tier to "apps/lxd".\nWrote /repo/pragma.config.json',
|
|
20
|
+
);
|
|
13
21
|
});
|
|
14
22
|
|
|
15
23
|
it("json returns valid JSON", () => {
|
|
16
24
|
const parsed = JSON.parse(formatters.set.json(data));
|
|
17
25
|
expect(parsed.field).toBe("tier");
|
|
18
26
|
expect(parsed.value).toBe("apps/lxd");
|
|
27
|
+
expect(parsed.path).toBe("/repo/pragma.config.json");
|
|
19
28
|
});
|
|
20
29
|
});
|
|
21
30
|
|
|
22
31
|
describe("tierFormatters.reset", () => {
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
const data = { field: "tier", path: "/repo/pragma.config.json" };
|
|
33
|
+
|
|
34
|
+
it("plain renders reset message with the written path", () => {
|
|
35
|
+
expect(formatters.reset.plain(data)).toBe(
|
|
36
|
+
"Reset tier to default.\nWrote /repo/pragma.config.json",
|
|
37
|
+
);
|
|
25
38
|
});
|
|
26
39
|
|
|
27
|
-
it("llm renders reset message", () => {
|
|
28
|
-
expect(formatters.reset.llm(
|
|
40
|
+
it("llm renders reset message with the written path", () => {
|
|
41
|
+
expect(formatters.reset.llm(data)).toBe(
|
|
42
|
+
"Reset tier to default.\nWrote /repo/pragma.config.json",
|
|
43
|
+
);
|
|
29
44
|
});
|
|
30
45
|
|
|
31
46
|
it("json returns valid JSON", () => {
|
|
32
|
-
const parsed = JSON.parse(formatters.reset.json(
|
|
47
|
+
const parsed = JSON.parse(formatters.reset.json(data));
|
|
33
48
|
expect(parsed.field).toBe("tier");
|
|
34
49
|
expect(parsed.reset).toBe(true);
|
|
50
|
+
expect(parsed.path).toBe("/repo/pragma.config.json");
|
|
35
51
|
});
|
|
36
52
|
});
|
|
37
53
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { Formatters } from "../../shared/formatters.js";
|
|
2
2
|
|
|
3
|
+
/** Payload for a persisted config write, including the file written. */
|
|
4
|
+
interface TierWrite {
|
|
5
|
+
readonly field: string;
|
|
6
|
+
readonly value: string;
|
|
7
|
+
readonly path: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
11
|
* Formatter sets for `pragma config tier` output, grouped by branch:
|
|
5
12
|
*
|
|
@@ -9,19 +16,20 @@ import type { Formatters } from "../../shared/formatters.js";
|
|
|
9
16
|
*/
|
|
10
17
|
const tierFormatters = {
|
|
11
18
|
set: {
|
|
12
|
-
plain: (d: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
JSON.stringify({ field: d.field, value: d.value }),
|
|
18
|
-
} satisfies Formatters<{ field: string; value: string }>,
|
|
19
|
+
plain: (d: TierWrite) => `Set ${d.field} to "${d.value}".\nWrote ${d.path}`,
|
|
20
|
+
llm: (d: TierWrite) => `Set ${d.field} to "${d.value}".\nWrote ${d.path}`,
|
|
21
|
+
json: (d: TierWrite) =>
|
|
22
|
+
JSON.stringify({ field: d.field, value: d.value, path: d.path }),
|
|
23
|
+
} satisfies Formatters<TierWrite>,
|
|
19
24
|
|
|
20
25
|
reset: {
|
|
21
|
-
plain: (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
plain: (d: { field: string; path: string }) =>
|
|
27
|
+
`Reset tier to default.\nWrote ${d.path}`,
|
|
28
|
+
llm: (d: { field: string; path: string }) =>
|
|
29
|
+
`Reset tier to default.\nWrote ${d.path}`,
|
|
30
|
+
json: (d: { field: string; path: string }) =>
|
|
31
|
+
JSON.stringify({ field: "tier", reset: true, path: d.path }),
|
|
32
|
+
} satisfies Formatters<{ field: string; path: string }>,
|
|
25
33
|
|
|
26
34
|
query: {
|
|
27
35
|
plain: (tier: string | undefined) =>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Formatters } from "../../shared/formatters.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Formatter sets for `pragma config trace` output, grouped by branch:
|
|
5
|
+
*
|
|
6
|
+
* - **set** formats the confirmation after enabling/disabling.
|
|
7
|
+
* - **query** formats the current trace status.
|
|
8
|
+
*/
|
|
9
|
+
const traceFormatters = {
|
|
10
|
+
set: {
|
|
11
|
+
plain: (d: { field: string; value: boolean; path: string }) =>
|
|
12
|
+
`${d.value ? "Tracing enabled." : "Tracing disabled."}\nWrote ${d.path}`,
|
|
13
|
+
llm: (d: { field: string; value: boolean; path: string }) =>
|
|
14
|
+
`${d.value ? "Tracing enabled." : "Tracing disabled."}\nWrote ${d.path}`,
|
|
15
|
+
json: (d: { field: string; value: boolean; path: string }) =>
|
|
16
|
+
JSON.stringify({ field: d.field, value: d.value, path: d.path }),
|
|
17
|
+
} satisfies Formatters<{ field: string; value: boolean; path: string }>,
|
|
18
|
+
|
|
19
|
+
query: {
|
|
20
|
+
plain: (status: string) => status,
|
|
21
|
+
llm: (status: string) => status,
|
|
22
|
+
// Emit the human-readable status under `status`, not `value`, so the JSON
|
|
23
|
+
// shape stays consistent with `set` (where `value` is the boolean state).
|
|
24
|
+
json: (status: string) => JSON.stringify({ field: "trace", status }),
|
|
25
|
+
} satisfies Formatters<string>,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default traceFormatters;
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import type { CommandDefinition } from "@canonical/cli-core";
|
|
4
4
|
import type { PragmaContext } from "../shared/context.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
channelCommand,
|
|
7
|
+
frameworkCommand,
|
|
8
|
+
showCommand,
|
|
9
|
+
tierCommand,
|
|
10
|
+
traceCommand,
|
|
11
|
+
} from "./commands/index.js";
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
14
|
* Return all config command definitions.
|
|
@@ -11,7 +17,13 @@ import { channelCommand, showCommand, tierCommand } from "./commands/index.js";
|
|
|
11
17
|
* @returns An array of CommandDefinitions for the config subcommands.
|
|
12
18
|
*/
|
|
13
19
|
export function commands(ctx: PragmaContext): CommandDefinition[] {
|
|
14
|
-
return [
|
|
20
|
+
return [
|
|
21
|
+
tierCommand(ctx),
|
|
22
|
+
channelCommand(ctx),
|
|
23
|
+
traceCommand(ctx),
|
|
24
|
+
frameworkCommand(ctx),
|
|
25
|
+
showCommand(ctx),
|
|
26
|
+
];
|
|
15
27
|
}
|
|
16
28
|
|
|
17
29
|
export { specs as mcpSpecs } from "./mcp/index.js";
|
|
@@ -19,5 +31,6 @@ export type { ConfigShowData } from "./operations/index.js";
|
|
|
19
31
|
export {
|
|
20
32
|
resolveConfigShow,
|
|
21
33
|
validateChannel,
|
|
34
|
+
validateFramework,
|
|
22
35
|
validateTier,
|
|
23
36
|
} from "./operations/index.js";
|
|
@@ -1,54 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP tool specs for the config domain
|
|
2
|
+
* MCP tool specs for the config domain — config_show, config_tier,
|
|
3
|
+
* config_channel.
|
|
3
4
|
*
|
|
4
|
-
* config_show
|
|
5
|
-
*
|
|
5
|
+
* config_show is compiled from the config read story in `../stories.ts`
|
|
6
|
+
* so both surfaces share resolution and formatters; the mutating tier and
|
|
7
|
+
* channel tools are spec'd by hand.
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
10
|
import { readConfig, writeConfig } from "#config";
|
|
9
|
-
import {
|
|
11
|
+
import { compileReadTool } from "../../shared/stories/index.js";
|
|
10
12
|
import type { ToolSpec } from "../../shared/ToolSpec.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
resolveConfigShow,
|
|
14
|
-
validateChannel,
|
|
15
|
-
validateTier,
|
|
16
|
-
} from "../operations/index.js";
|
|
13
|
+
import { validateChannel, validateTier } from "../operations/index.js";
|
|
14
|
+
import { configShowStory } from "../stories.js";
|
|
17
15
|
|
|
18
16
|
const specs: readonly ToolSpec[] = [
|
|
19
|
-
|
|
20
|
-
name: "config_show",
|
|
21
|
-
description:
|
|
22
|
-
"Show current pragma configuration (tier and channel settings).",
|
|
23
|
-
params: {
|
|
24
|
-
condensed: {
|
|
25
|
-
type: "boolean",
|
|
26
|
-
description: "Token-optimized output",
|
|
27
|
-
optional: true,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
readOnly: true,
|
|
31
|
-
async execute(rt, { condensed }) {
|
|
32
|
-
const install = detectInstallSource();
|
|
33
|
-
const data = resolveConfigShow(rt.config, {
|
|
34
|
-
packageManager: install.packageManager,
|
|
35
|
-
installSource: install.label,
|
|
36
|
-
configFilePath: "pragma.config.json",
|
|
37
|
-
configFileExists: true,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (condensed) {
|
|
41
|
-
const text = showFormatters.llm(data);
|
|
42
|
-
return {
|
|
43
|
-
condensed: true,
|
|
44
|
-
text,
|
|
45
|
-
tokens: `~${Math.ceil(text.length / 4)}`,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return { data };
|
|
50
|
-
},
|
|
51
|
-
},
|
|
17
|
+
compileReadTool(configShowStory),
|
|
52
18
|
{
|
|
53
19
|
name: "config_tier",
|
|
54
20
|
description:
|
|
@@ -64,18 +30,25 @@ const specs: readonly ToolSpec[] = [
|
|
|
64
30
|
description: "Reset tier to default",
|
|
65
31
|
optional: true,
|
|
66
32
|
},
|
|
33
|
+
global: {
|
|
34
|
+
type: "boolean",
|
|
35
|
+
description: "Write to the global config instead of the project file",
|
|
36
|
+
optional: true,
|
|
37
|
+
},
|
|
67
38
|
},
|
|
68
39
|
readOnly: false,
|
|
69
|
-
async execute(rt, { path, reset }) {
|
|
40
|
+
async execute(rt, { path, reset, global: globalScope }) {
|
|
41
|
+
const scope = globalScope === true ? "global" : undefined;
|
|
42
|
+
|
|
70
43
|
if (reset) {
|
|
71
|
-
writeConfig(rt.cwd, { tier: undefined });
|
|
72
|
-
return { data: { tier: null, action: "reset" } };
|
|
44
|
+
const written = writeConfig(rt.cwd, { tier: undefined }, scope);
|
|
45
|
+
return { data: { tier: null, action: "reset", path: written } };
|
|
73
46
|
}
|
|
74
47
|
|
|
75
48
|
if (path) {
|
|
76
49
|
await validateTier(rt.store, path as string);
|
|
77
|
-
writeConfig(rt.cwd, { tier: path as string });
|
|
78
|
-
return { data: { tier: path, action: "set" } };
|
|
50
|
+
const written = writeConfig(rt.cwd, { tier: path as string }, scope);
|
|
51
|
+
return { data: { tier: path, action: "set", path: written } };
|
|
79
52
|
}
|
|
80
53
|
|
|
81
54
|
const config = readConfig(rt.cwd);
|
|
@@ -97,18 +70,25 @@ const specs: readonly ToolSpec[] = [
|
|
|
97
70
|
description: "Reset channel to normal",
|
|
98
71
|
optional: true,
|
|
99
72
|
},
|
|
73
|
+
global: {
|
|
74
|
+
type: "boolean",
|
|
75
|
+
description: "Write to the global config instead of the project file",
|
|
76
|
+
optional: true,
|
|
77
|
+
},
|
|
100
78
|
},
|
|
101
79
|
readOnly: false,
|
|
102
|
-
async execute(rt, { value, reset }) {
|
|
80
|
+
async execute(rt, { value, reset, global: globalScope }) {
|
|
81
|
+
const scope = globalScope === true ? "global" : undefined;
|
|
82
|
+
|
|
103
83
|
if (reset) {
|
|
104
|
-
writeConfig(rt.cwd, { channel: undefined });
|
|
105
|
-
return { data: { channel: "normal", action: "reset" } };
|
|
84
|
+
const written = writeConfig(rt.cwd, { channel: undefined }, scope);
|
|
85
|
+
return { data: { channel: "normal", action: "reset", path: written } };
|
|
106
86
|
}
|
|
107
87
|
|
|
108
88
|
if (value) {
|
|
109
89
|
const channel = validateChannel(value as string);
|
|
110
|
-
writeConfig(rt.cwd, { channel });
|
|
111
|
-
return { data: { channel, action: "set" } };
|
|
90
|
+
const written = writeConfig(rt.cwd, { channel }, scope);
|
|
91
|
+
return { data: { channel, action: "set", path: written } };
|
|
112
92
|
}
|
|
113
93
|
|
|
114
94
|
const config = readConfig(rt.cwd);
|
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
export { default as resolveConfigShow } from "./show.js";
|
|
3
3
|
export type { ConfigShowData } from "./types.js";
|
|
4
4
|
export { default as validateChannel } from "./validateChannel.js";
|
|
5
|
+
export { default as validateFramework } from "./validateFramework.js";
|
|
5
6
|
export { default as validateTier } from "./validateTier.js";
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
+
import type { ConfigOrigins } from "#config";
|
|
2
3
|
import resolveConfigShow from "./show.js";
|
|
3
4
|
|
|
5
|
+
const PROJECT_ORIGINS: ConfigOrigins = {
|
|
6
|
+
tier: "project",
|
|
7
|
+
channel: "project",
|
|
8
|
+
packages: "default",
|
|
9
|
+
trace: "default",
|
|
10
|
+
framework: "default",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const PROVENANCE = {
|
|
14
|
+
globalConfigPath: "/home/u/.config/pragma/config.json",
|
|
15
|
+
globalConfigExists: false,
|
|
16
|
+
origins: PROJECT_ORIGINS,
|
|
17
|
+
};
|
|
18
|
+
|
|
4
19
|
describe("resolveConfigShow", () => {
|
|
5
20
|
it("resolves tier chain and included releases", () => {
|
|
6
21
|
const data = resolveConfigShow(
|
|
@@ -10,6 +25,7 @@ describe("resolveConfigShow", () => {
|
|
|
10
25
|
installSource: "bun (global)",
|
|
11
26
|
configFilePath: "/tmp/pragma.config.json",
|
|
12
27
|
configFileExists: true,
|
|
28
|
+
...PROVENANCE,
|
|
13
29
|
},
|
|
14
30
|
);
|
|
15
31
|
|
|
@@ -30,6 +46,7 @@ describe("resolveConfigShow", () => {
|
|
|
30
46
|
installSource: "bun (local)",
|
|
31
47
|
configFilePath: "/tmp/pragma.config.json",
|
|
32
48
|
configFileExists: false,
|
|
49
|
+
...PROVENANCE,
|
|
33
50
|
},
|
|
34
51
|
);
|
|
35
52
|
|
|
@@ -47,6 +64,7 @@ describe("resolveConfigShow", () => {
|
|
|
47
64
|
installSource: "pnpm (global)",
|
|
48
65
|
configFilePath: "/tmp/pragma.config.json",
|
|
49
66
|
configFileExists: true,
|
|
67
|
+
...PROVENANCE,
|
|
50
68
|
},
|
|
51
69
|
);
|
|
52
70
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PragmaConfig } from "#config";
|
|
1
|
+
import type { ConfigOrigins, PragmaConfig } from "#config";
|
|
2
2
|
import { CHANNEL_RELEASES } from "../../shared/filters/buildChannelFilter.js";
|
|
3
3
|
import { resolveTierChain } from "../../shared/filters/buildTierFilter.js";
|
|
4
4
|
import type { ConfigShowData } from "./types.js";
|
|
@@ -20,6 +20,9 @@ export default function resolveConfigShow(
|
|
|
20
20
|
installSource: string;
|
|
21
21
|
configFilePath: string;
|
|
22
22
|
configFileExists: boolean;
|
|
23
|
+
globalConfigPath: string;
|
|
24
|
+
globalConfigExists: boolean;
|
|
25
|
+
origins: ConfigOrigins;
|
|
23
26
|
},
|
|
24
27
|
): ConfigShowData {
|
|
25
28
|
// Don't throw for stale config — show always displays what's configured.
|
|
@@ -38,5 +41,8 @@ export default function resolveConfigShow(
|
|
|
38
41
|
installSource: opts.installSource,
|
|
39
42
|
configFilePath: opts.configFilePath,
|
|
40
43
|
configFileExists: opts.configFileExists,
|
|
44
|
+
globalConfigPath: opts.globalConfigPath,
|
|
45
|
+
globalConfigExists: opts.globalConfigExists,
|
|
46
|
+
origins: opts.origins,
|
|
41
47
|
};
|
|
42
48
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConfigOrigins } from "#config";
|
|
1
2
|
import type { Channel } from "#constants";
|
|
2
3
|
|
|
3
4
|
/** Data returned by `pragma config show`, including resolved tier chain and channel releases. */
|
|
@@ -8,6 +9,12 @@ export interface ConfigShowData {
|
|
|
8
9
|
readonly includedReleases: readonly string[];
|
|
9
10
|
readonly packageManager: string;
|
|
10
11
|
readonly installSource: string;
|
|
12
|
+
/** Nearest project config file (or the would-be path at cwd). */
|
|
11
13
|
readonly configFilePath: string;
|
|
12
14
|
readonly configFileExists: boolean;
|
|
15
|
+
/** The global XDG config file. */
|
|
16
|
+
readonly globalConfigPath: string;
|
|
17
|
+
readonly globalConfigExists: boolean;
|
|
18
|
+
/** Which layer supplied each effective field. */
|
|
19
|
+
readonly origins: ConfigOrigins;
|
|
13
20
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Framework, VALID_FRAMEWORKS } from "#constants";
|
|
2
|
+
import { PragmaError } from "#error";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validate that a string is one of the accepted framework values.
|
|
6
|
+
*
|
|
7
|
+
* @param value - The framework string to validate.
|
|
8
|
+
* @returns The validated Framework value.
|
|
9
|
+
* @throws PragmaError.invalidInput if the value is not a valid framework.
|
|
10
|
+
*/
|
|
11
|
+
export default function validateFramework(value: string): Framework {
|
|
12
|
+
if (VALID_FRAMEWORKS.includes(value as Framework)) {
|
|
13
|
+
return value as Framework;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
throw PragmaError.invalidInput("framework", value, {
|
|
17
|
+
validOptions: [...VALID_FRAMEWORKS],
|
|
18
|
+
recovery: {
|
|
19
|
+
message: "Reset framework configuration.",
|
|
20
|
+
cli: "pragma config framework --reset",
|
|
21
|
+
mcp: { tool: "config_framework", params: { reset: true } },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config read story — the single declaration of `config show` for both
|
|
3
|
+
* surfaces.
|
|
4
|
+
*
|
|
5
|
+
* Both surfaces resolve from the filesystem, so the MCP tool now reports
|
|
6
|
+
* the real config path and existence (it previously hardcoded
|
|
7
|
+
* `pragma.config.json` / `true` regardless of the working directory).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readConfigLayers } from "#config";
|
|
11
|
+
import { detectInstallSource } from "#package-manager";
|
|
12
|
+
import type { ReadStory } from "../shared/stories/index.js";
|
|
13
|
+
import { showFormatters } from "./formatters/index.js";
|
|
14
|
+
import { resolveConfigShow } from "./operations/index.js";
|
|
15
|
+
import type { ConfigShowData } from "./operations/types.js";
|
|
16
|
+
|
|
17
|
+
/** The `config show` / `config_show` read story. */
|
|
18
|
+
export const configShowStory: ReadStory<ConfigShowData, ConfigShowData> = {
|
|
19
|
+
noun: "config",
|
|
20
|
+
verb: "show",
|
|
21
|
+
description: "Display resolved configuration",
|
|
22
|
+
toolDescription:
|
|
23
|
+
"Show current pragma configuration (tier and channel settings).",
|
|
24
|
+
params: [],
|
|
25
|
+
examples: ["pragma config show"],
|
|
26
|
+
resolve: async (rt) => {
|
|
27
|
+
const layers = readConfigLayers(rt.cwd);
|
|
28
|
+
const install = detectInstallSource();
|
|
29
|
+
return resolveConfigShow(layers.config, {
|
|
30
|
+
packageManager: install.packageManager,
|
|
31
|
+
installSource: install.label,
|
|
32
|
+
configFilePath: layers.project.path,
|
|
33
|
+
configFileExists: layers.project.exists,
|
|
34
|
+
globalConfigPath: layers.global.path,
|
|
35
|
+
globalConfigExists: layers.global.exists,
|
|
36
|
+
origins: layers.origins,
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
toOutput: (data) => data,
|
|
40
|
+
formatters: showFormatters,
|
|
41
|
+
toEnvelope: (data) => ({ data }),
|
|
42
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
/** @module Config write tasks. */
|
|
2
2
|
export { default as setChannelTask } from "./setChannel.js";
|
|
3
|
+
export { default as setFrameworkTask } from "./setFramework.js";
|
|
3
4
|
export { default as setTierTask } from "./setTier.js";
|
|
5
|
+
export { default as setTraceTask } from "./setTrace.js";
|
|
6
|
+
export { default as writeConfigFieldTask } from "./writeConfigField.js";
|
|
@@ -1,30 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import type { Task } from "@canonical/task";
|
|
2
|
+
import type { ConfigScope } from "../../../config/index.js";
|
|
3
|
+
import type { Channel } from "../../../constants.js";
|
|
4
|
+
import writeConfigField from "./writeConfigField.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Build a config-write task for setting or resetting the release channel.
|
|
7
8
|
*
|
|
8
|
-
* @param cwd - Working directory
|
|
9
|
-
* @param channel - Channel
|
|
10
|
-
* @
|
|
11
|
-
* @
|
|
9
|
+
* @param cwd - Working directory the target config layer is resolved from.
|
|
10
|
+
* @param channel - Channel to persist, or `undefined` to reset.
|
|
11
|
+
* @param scope - Optional explicit target layer (`"global"` | `"local"`).
|
|
12
|
+
* @returns Task yielding the persisted field/value payload and target path.
|
|
13
|
+
* @note - Impure — reads and writes the target config file.
|
|
12
14
|
*/
|
|
13
15
|
export default function setChannel(
|
|
14
16
|
cwd: string,
|
|
15
|
-
channel:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const next = {
|
|
20
|
-
...(current.tier !== undefined ? { tier: current.tier } : {}),
|
|
21
|
-
...(channel !== undefined ? { channel } : {}),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
yield* $(
|
|
25
|
-
writeFile(resolveConfigPath(cwd), `${JSON.stringify(next, null, 2)}\n`),
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
return { field: "channel", value: channel };
|
|
29
|
-
});
|
|
17
|
+
channel: Channel | undefined,
|
|
18
|
+
scope?: ConfigScope,
|
|
19
|
+
): Task<{ field: "channel"; value: Channel | undefined; path: string }> {
|
|
20
|
+
return writeConfigField(cwd, "channel", channel, scope);
|
|
30
21
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Task } from "@canonical/task";
|
|
2
|
+
import type { ConfigScope } from "../../../config/index.js";
|
|
3
|
+
import type { Framework } from "../../../constants.js";
|
|
4
|
+
import writeConfigField from "./writeConfigField.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Build a config-write task for setting or resetting the preferred framework.
|
|
8
|
+
*
|
|
9
|
+
* @param cwd - Working directory the target config layer is resolved from.
|
|
10
|
+
* @param framework - Framework to persist, or `undefined` to reset.
|
|
11
|
+
* @param scope - Optional explicit target layer (`"global"` | `"local"`).
|
|
12
|
+
* @returns Task yielding the persisted field/value payload and target path.
|
|
13
|
+
* @note - Impure — reads and writes the target config file.
|
|
14
|
+
*/
|
|
15
|
+
export default function setFramework(
|
|
16
|
+
cwd: string,
|
|
17
|
+
framework: Framework | undefined,
|
|
18
|
+
scope?: ConfigScope,
|
|
19
|
+
): Task<{ field: "framework"; value: Framework | undefined; path: string }> {
|
|
20
|
+
return writeConfigField(cwd, "framework", framework, scope);
|
|
21
|
+
}
|
|
@@ -1,33 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import type { Task } from "@canonical/task";
|
|
2
|
+
import type { ConfigScope } from "../../../config/index.js";
|
|
3
|
+
import writeConfigField from "./writeConfigField.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Build a config-write task for setting or resetting the active tier.
|
|
7
7
|
*
|
|
8
|
-
* @param cwd - Working directory
|
|
8
|
+
* @param cwd - Working directory the target config layer is resolved from.
|
|
9
9
|
* @param tier - Tier path to persist, or `undefined` to reset.
|
|
10
|
-
* @
|
|
11
|
-
* @
|
|
10
|
+
* @param scope - Optional explicit target layer (`"global"` | `"local"`).
|
|
11
|
+
* @returns Task yielding the persisted field/value payload and target path.
|
|
12
|
+
* @note - Impure — reads and writes the target config file.
|
|
12
13
|
*/
|
|
13
14
|
export default function setTier(
|
|
14
15
|
cwd: string,
|
|
15
16
|
tier: string | undefined,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}> {
|
|
20
|
-
return gen(function* () {
|
|
21
|
-
const current = readConfig(cwd);
|
|
22
|
-
const next = {
|
|
23
|
-
...(tier !== undefined ? { tier } : {}),
|
|
24
|
-
...(current.channel !== undefined ? { channel: current.channel } : {}),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
yield* $(
|
|
28
|
-
writeFile(resolveConfigPath(cwd), `${JSON.stringify(next, null, 2)}\n`),
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
return { field: "tier", value: tier };
|
|
32
|
-
});
|
|
17
|
+
scope?: ConfigScope,
|
|
18
|
+
): Task<{ field: "tier"; value: string | undefined; path: string }> {
|
|
19
|
+
return writeConfigField(cwd, "tier", tier, scope);
|
|
33
20
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Task } from "@canonical/task";
|
|
2
|
+
import type { ConfigScope } from "../../../config/index.js";
|
|
3
|
+
import writeConfigField from "./writeConfigField.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build a config-write task for enabling or disabling query tracing.
|
|
7
|
+
*
|
|
8
|
+
* @param cwd - Working directory the target config layer is resolved from.
|
|
9
|
+
* @param trace - `true` to enable, `false` to disable.
|
|
10
|
+
* @param scope - Optional explicit target layer (`"global"` | `"local"`).
|
|
11
|
+
* @returns Task yielding the persisted field/value payload and target path.
|
|
12
|
+
* @note - Impure — reads and writes the target config file.
|
|
13
|
+
*/
|
|
14
|
+
export default function setTrace(
|
|
15
|
+
cwd: string,
|
|
16
|
+
trace: boolean,
|
|
17
|
+
scope?: ConfigScope,
|
|
18
|
+
): Task<{ field: "trace"; value: boolean | undefined; path: string }> {
|
|
19
|
+
return writeConfigField(cwd, "trace", trace, scope);
|
|
20
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { $, gen, type Task, writeFile } from "@canonical/task";
|
|
2
|
+
import {
|
|
3
|
+
type ConfigScope,
|
|
4
|
+
type ConfigUpdate,
|
|
5
|
+
mergeConfigFileUpdate,
|
|
6
|
+
resolveWriteConfigPath,
|
|
7
|
+
} from "../../../config/index.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Build a config-write task for one field.
|
|
11
|
+
*
|
|
12
|
+
* Resolves the target layer with the global-first write rule (explicit
|
|
13
|
+
* scope wins, else the nearest existing project file, else the global XDG
|
|
14
|
+
* file), merges the update into that file's own contents — never copying
|
|
15
|
+
* values from another layer — and writes through the tracked `writeFile`
|
|
16
|
+
* effect so the change participates in dry-run and undo. `undefined`
|
|
17
|
+
* removes the field from the target file.
|
|
18
|
+
*
|
|
19
|
+
* @param cwd - Working directory the project layer is resolved from.
|
|
20
|
+
* @param field - Config field to set or remove.
|
|
21
|
+
* @param value - New value, or `undefined` to remove the field.
|
|
22
|
+
* @param scope - Optional explicit target layer.
|
|
23
|
+
* @returns Task yielding the persisted field/value payload and the path written.
|
|
24
|
+
* @note Impure — resolves and reads the target file, writes via effect.
|
|
25
|
+
*/
|
|
26
|
+
export default function writeConfigField<F extends keyof ConfigUpdate>(
|
|
27
|
+
cwd: string,
|
|
28
|
+
field: F,
|
|
29
|
+
value: ConfigUpdate[F],
|
|
30
|
+
scope?: ConfigScope,
|
|
31
|
+
): Task<{ field: F; value: ConfigUpdate[F]; path: string }> {
|
|
32
|
+
return gen(function* () {
|
|
33
|
+
const path = resolveWriteConfigPath(cwd, scope);
|
|
34
|
+
const update = { [field]: value } as ConfigUpdate;
|
|
35
|
+
const content = mergeConfigFileUpdate(path, update);
|
|
36
|
+
|
|
37
|
+
yield* $(writeFile(path, content));
|
|
38
|
+
|
|
39
|
+
return { field, value, path };
|
|
40
|
+
});
|
|
41
|
+
}
|