@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.
Files changed (410) hide show
  1. package/README.md +128 -47
  2. package/dist/pragma +0 -0
  3. package/package.json +15 -13
  4. package/src/completions/constants.ts +7 -0
  5. package/src/completions/handleQuery.test.ts +32 -0
  6. package/src/completions/handleQuery.ts +20 -1
  7. package/src/completions/queryCompletions.test.ts +5 -0
  8. package/src/completions/queryCompletions.ts +17 -3
  9. package/src/completions/querySocket.test.ts +31 -0
  10. package/src/completions/querySocket.ts +36 -9
  11. package/src/config/defaultConfig.test.ts +33 -0
  12. package/src/config/defaultConfig.ts +59 -0
  13. package/src/config/defaults.json +17 -0
  14. package/src/config/findProjectConfigPath.test.ts +53 -0
  15. package/src/config/findProjectConfigPath.ts +36 -0
  16. package/src/config/index.ts +17 -2
  17. package/src/config/mergeConfigFileUpdate.ts +58 -0
  18. package/src/config/parseConfigValues.ts +217 -0
  19. package/src/config/readConfig.test.ts +104 -13
  20. package/src/config/readConfig.ts +12 -153
  21. package/src/config/readConfigLayers.test.ts +109 -0
  22. package/src/config/readConfigLayers.ts +118 -0
  23. package/src/config/resolveGlobalConfigPath.ts +13 -0
  24. package/src/config/resolveWriteConfigPath.test.ts +53 -0
  25. package/src/config/resolveWriteConfigPath.ts +31 -0
  26. package/src/config/types.ts +83 -1
  27. package/src/config/writeConfig.ts +25 -55
  28. package/src/constants.ts +3 -1
  29. package/src/domains/block/commands/list.ts +5 -90
  30. package/src/domains/block/commands/lookup.ts +8 -167
  31. package/src/domains/block/commands/sample.ts +2 -1
  32. package/src/domains/block/formatters/list.test.ts +3 -3
  33. package/src/domains/block/formatters/lookup.test.ts +5 -5
  34. package/src/domains/block/mcp/specs.ts +16 -196
  35. package/src/domains/block/orchestration/enrichBlocks.ts +6 -3
  36. package/src/domains/block/orchestration/resolveBlockLookup.ts +2 -1
  37. package/src/domains/block/stories.test.ts +28 -0
  38. package/src/domains/block/stories.ts +260 -0
  39. package/src/domains/config/commands/channel.test.ts +30 -3
  40. package/src/domains/config/commands/channel.ts +25 -8
  41. package/src/domains/config/commands/configScope.ts +46 -0
  42. package/src/domains/config/commands/framework.test.ts +32 -1
  43. package/src/domains/config/commands/framework.ts +26 -8
  44. package/src/domains/config/commands/show.ts +5 -45
  45. package/src/domains/config/commands/tier.test.ts +20 -2
  46. package/src/domains/config/commands/tier.ts +25 -8
  47. package/src/domains/config/commands/trace.test.ts +19 -2
  48. package/src/domains/config/commands/trace.ts +6 -3
  49. package/src/domains/config/formatters/channel.test.ts +20 -6
  50. package/src/domains/config/formatters/channel.ts +14 -11
  51. package/src/domains/config/formatters/framework.ts +14 -11
  52. package/src/domains/config/formatters/show.test.ts +27 -0
  53. package/src/domains/config/formatters/show.ts +27 -4
  54. package/src/domains/config/formatters/tier.test.ts +26 -10
  55. package/src/domains/config/formatters/tier.ts +19 -11
  56. package/src/domains/config/formatters/trace.ts +7 -7
  57. package/src/domains/config/mcp/specs.ts +33 -53
  58. package/src/domains/config/operations/show.test.ts +18 -0
  59. package/src/domains/config/operations/show.ts +7 -1
  60. package/src/domains/config/operations/types.ts +7 -0
  61. package/src/domains/config/operations/validateTier.test.ts +9 -0
  62. package/src/domains/config/operations/validateTier.ts +10 -2
  63. package/src/domains/config/stories.ts +42 -0
  64. package/src/domains/config/tasks/index.ts +1 -0
  65. package/src/domains/config/tasks/setChannel.ts +13 -28
  66. package/src/domains/config/tasks/setFramework.ts +11 -30
  67. package/src/domains/config/tasks/setTier.ts +10 -29
  68. package/src/domains/config/tasks/setTrace.ts +10 -28
  69. package/src/domains/config/tasks/writeConfigField.ts +41 -0
  70. package/src/domains/create/generatorPack/bundled.ts +49 -0
  71. package/src/domains/create/generatorPack/compileGeneratorPack.test.ts +159 -0
  72. package/src/domains/create/generatorPack/compileGeneratorPack.ts +312 -0
  73. package/src/domains/create/index.ts +13 -7
  74. package/src/domains/create/mcp/specs.ts +6 -161
  75. package/src/domains/create/renderGeneratorUi.test.ts +103 -0
  76. package/src/domains/create/renderGeneratorUi.ts +65 -0
  77. package/src/domains/doctor/formatters/doctor.test.ts +50 -2
  78. package/src/domains/doctor/formatters/doctor.ts +90 -38
  79. package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
  80. package/src/domains/doctor/operations/checks/checkMcpCommands.ts +133 -0
  81. package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
  82. package/src/domains/doctor/operations/checks/checkPackageRefs.ts +32 -26
  83. package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +1 -1
  84. package/src/domains/doctor/operations/checks/index.ts +1 -0
  85. package/src/domains/doctor/operations/checks.test.ts +160 -7
  86. package/src/domains/doctor/operations/runChecks.test.ts +15 -6
  87. package/src/domains/doctor/operations/runChecks.ts +2 -0
  88. package/src/domains/doctor/operations/types.ts +23 -1
  89. package/src/domains/graph/commands/inspect.test.ts +2 -2
  90. package/src/domains/graph/commands/query.test.ts +5 -3
  91. package/src/domains/graph/formatters/inspect.ts +7 -7
  92. package/src/domains/graph/formatters/query.test.ts +87 -0
  93. package/src/domains/graph/formatters/query.ts +42 -5
  94. package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
  95. package/src/domains/graph/helpers/resolveUri.ts +28 -21
  96. package/src/domains/graph/operations/inspectUri.test.ts +5 -5
  97. package/src/domains/graphql/commands/build.test.ts +5 -3
  98. package/src/domains/graphql/commands/build.ts +8 -16
  99. package/src/domains/graphql/commands/check.test.ts +5 -3
  100. package/src/domains/graphql/commands/check.ts +7 -13
  101. package/src/domains/graphql/commands/index.ts +1 -0
  102. package/src/domains/graphql/commands/serve.test.ts +46 -0
  103. package/src/domains/graphql/commands/serve.ts +141 -0
  104. package/src/domains/graphql/constants.ts +10 -0
  105. package/src/domains/graphql/helpers/gatherSources.test.ts +92 -0
  106. package/src/domains/graphql/helpers/gatherSources.ts +58 -0
  107. package/src/domains/graphql/helpers/index.ts +2 -0
  108. package/src/domains/graphql/helpers/parsePrefixes.test.ts +3 -3
  109. package/src/domains/graphql/helpers/parsePrefixes.ts +3 -3
  110. package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +9 -0
  111. package/src/domains/graphql/helpers/resolveSourceFiles.ts +24 -3
  112. package/src/domains/graphql/helpers/routeGraphql.test.ts +43 -0
  113. package/src/domains/graphql/helpers/routeGraphql.ts +28 -0
  114. package/src/domains/graphql/index.ts +9 -6
  115. package/src/domains/graphql/operations/compileSchema.test.ts +23 -47
  116. package/src/domains/graphql/operations/compileSchema.ts +23 -25
  117. package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
  118. package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
  119. package/src/domains/graphql/operations/ensureSchemaArtifact.test.ts +167 -0
  120. package/src/domains/graphql/operations/ensureSchemaArtifact.ts +178 -0
  121. package/src/domains/graphql/operations/index.ts +10 -0
  122. package/src/domains/info/formatters/upgrade.test.ts +7 -4
  123. package/src/domains/info/formatters/upgrade.ts +3 -1
  124. package/src/domains/info/operations/collectEntityCounts.test.ts +156 -0
  125. package/src/domains/info/operations/collectEntityCounts.ts +123 -0
  126. package/src/domains/info/operations/collectInfo.test.ts +14 -3
  127. package/src/domains/info/operations/collectInfo.ts +12 -15
  128. package/src/domains/info/operations/index.ts +1 -0
  129. package/src/domains/info/types.ts +13 -0
  130. package/src/domains/llm/capabilities.test.ts +24 -4
  131. package/src/domains/llm/commands/capabilities.ts +12 -3
  132. package/src/domains/llm/commands/llm.ts +5 -1
  133. package/src/domains/llm/data/commandReference.ts +20 -11
  134. package/src/domains/llm/data/decisionTrees.ts +10 -5
  135. package/src/domains/llm/data/toolCatalog.ts +55 -18
  136. package/src/domains/llm/formatters/orientation.ts +5 -1
  137. package/src/domains/llm/llmCommand.test.ts +11 -3
  138. package/src/domains/llm/mcp/specs.ts +3 -4
  139. package/src/domains/llm/operations/collectContext.test.ts +64 -0
  140. package/src/domains/llm/operations/collectContext.ts +7 -17
  141. package/src/domains/modifier/commands/list.ts +5 -38
  142. package/src/domains/modifier/commands/lookup.ts +8 -79
  143. package/src/domains/modifier/commands/sample.ts +2 -1
  144. package/src/domains/modifier/mcp/specs.ts +15 -94
  145. package/src/domains/modifier/operations/lookup.ts +5 -3
  146. package/src/domains/modifier/orchestration/resolveModifierLookup.ts +2 -1
  147. package/src/domains/modifier/stories.test.ts +20 -0
  148. package/src/domains/modifier/stories.ts +86 -0
  149. package/src/domains/ontology/commands/list.test.ts +5 -3
  150. package/src/domains/ontology/commands/list.ts +5 -58
  151. package/src/domains/ontology/commands/show.test.ts +85 -9
  152. package/src/domains/ontology/commands/show.ts +6 -58
  153. package/src/domains/ontology/formatters/index.ts +1 -0
  154. package/src/domains/ontology/formatters/list.ts +37 -12
  155. package/src/domains/ontology/formatters/show.ts +361 -64
  156. package/src/domains/ontology/helpers/buildClassTree.ts +89 -0
  157. package/src/domains/ontology/helpers/completeClassNames.ts +43 -0
  158. package/src/domains/ontology/helpers/expandOntologyIris.ts +79 -0
  159. package/src/domains/ontology/helpers/index.ts +14 -0
  160. package/src/domains/ontology/helpers/queryClasses.ts +32 -16
  161. package/src/domains/ontology/helpers/queryProperties.ts +39 -6
  162. package/src/domains/ontology/helpers/queryTboxFacts.ts +160 -0
  163. package/src/domains/ontology/mcp/specs.ts +7 -84
  164. package/src/domains/ontology/operations/listOntologies.test.ts +80 -3
  165. package/src/domains/ontology/operations/listOntologies.ts +126 -30
  166. package/src/domains/ontology/operations/showOntology.test.ts +131 -12
  167. package/src/domains/ontology/operations/showOntology.ts +289 -7
  168. package/src/domains/ontology/operations/showOntologyRaw.test.ts +4 -2
  169. package/src/domains/ontology/stories.test.ts +36 -0
  170. package/src/domains/ontology/stories.ts +153 -0
  171. package/src/domains/refs/operations/updateRefs.ts +2 -38
  172. package/src/domains/setup/commands/index.ts +1 -0
  173. package/src/domains/setup/commands/setup.ts +70 -0
  174. package/src/domains/setup/commands/skills.test.ts +6 -2
  175. package/src/domains/setup/commands/skills.ts +6 -2
  176. package/src/domains/setup/helpers/runSetupTask.test.ts +148 -150
  177. package/src/domains/setup/helpers/runSetupTask.ts +62 -70
  178. package/src/domains/setup/index.ts +7 -3
  179. package/src/domains/setup/operations/setupLsp.test.ts +3 -2
  180. package/src/domains/setup/operations/setupLsp.ts +7 -2
  181. package/src/domains/setup/operations/setupMcp.test.ts +6 -1
  182. package/src/domains/shared/bootStore.bareCore.test.ts +63 -0
  183. package/src/domains/shared/bootStore.test.ts +82 -0
  184. package/src/domains/shared/bootStore.ts +57 -18
  185. package/src/domains/shared/compactUri.test.ts +11 -0
  186. package/src/domains/shared/compactUri.ts +10 -5
  187. package/src/domains/shared/context.ts +2 -2
  188. package/src/domains/shared/contracts.ts +11 -0
  189. package/src/domains/shared/createInteractivePromptSession.test.ts +439 -0
  190. package/src/domains/shared/createInteractivePromptSession.ts +236 -0
  191. package/src/domains/shared/emptyErrorRecovery.test.ts +23 -26
  192. package/src/domains/shared/extractLocalName.test.ts +3 -3
  193. package/src/domains/shared/formatters.ts +23 -2
  194. package/src/domains/shared/listTiers.ts +40 -0
  195. package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
  196. package/src/domains/shared/loaders/bundledLoader.ts +158 -12
  197. package/src/domains/shared/loaders/gitLoader.ts +1 -2
  198. package/src/domains/shared/loaders/index.ts +4 -1
  199. package/src/domains/shared/loaders/localLoader.ts +2 -4
  200. package/src/domains/shared/loaders/readPackageDir.test.ts +58 -0
  201. package/src/domains/shared/loaders/readPackageDir.ts +82 -9
  202. package/src/domains/shared/loaders/storyAssetsPlugin.test.ts +84 -0
  203. package/src/domains/shared/loaders/storyAssetsPlugin.ts +46 -0
  204. package/src/domains/shared/lookupMany.test.ts +135 -0
  205. package/src/domains/shared/lookupMany.ts +50 -2
  206. package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
  207. package/src/domains/shared/mergeAndParseRefs.ts +44 -0
  208. package/src/domains/shared/namespaces.ts +13 -5
  209. package/src/domains/shared/packages.ts +10 -17
  210. package/src/domains/shared/parseSampleCount.test.ts +47 -0
  211. package/src/domains/shared/parseSampleCount.ts +45 -0
  212. package/src/domains/shared/prefixes.test.ts +211 -0
  213. package/src/domains/shared/prefixes.ts +182 -15
  214. package/src/domains/shared/renderers.ts +5 -5
  215. package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
  216. package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
  217. package/src/domains/shared/resolveLookupExitCode.test.ts +48 -0
  218. package/src/domains/shared/resolveLookupExitCode.ts +42 -0
  219. package/src/domains/shared/runtime.ts +4 -63
  220. package/src/domains/shared/semanticPackage.test.ts +89 -0
  221. package/src/domains/shared/semanticPackage.ts +34 -3
  222. package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
  223. package/src/domains/shared/stories/compileLookupCommand.ts +102 -0
  224. package/src/domains/shared/stories/compileLookupTool.test.ts +105 -0
  225. package/src/domains/shared/stories/compileLookupTool.ts +96 -0
  226. package/src/domains/shared/stories/compileReadCommand.test.ts +121 -0
  227. package/src/domains/shared/stories/compileReadCommand.ts +48 -0
  228. package/src/domains/shared/stories/compileReadTool.test.ts +64 -0
  229. package/src/domains/shared/stories/compileReadTool.ts +38 -0
  230. package/src/domains/shared/stories/condense.test.ts +18 -0
  231. package/src/domains/shared/stories/condense.ts +15 -0
  232. package/src/domains/shared/stories/index.ts +20 -0
  233. package/src/domains/shared/stories/normalizeNames.test.ts +20 -0
  234. package/src/domains/shared/stories/normalizeNames.ts +22 -0
  235. package/src/domains/shared/stories/pack/applyPackFilters.test.ts +151 -0
  236. package/src/domains/shared/stories/pack/applyPackFilters.ts +111 -0
  237. package/src/domains/shared/stories/pack/applyPackSearch.test.ts +57 -0
  238. package/src/domains/shared/stories/pack/applyPackSearch.ts +41 -0
  239. package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +81 -0
  240. package/src/domains/shared/stories/pack/buildLookupQuery.ts +154 -0
  241. package/src/domains/shared/stories/pack/bundled/index.ts +23 -0
  242. package/src/domains/shared/stories/pack/bundled/standardPack.ts +164 -0
  243. package/src/domains/shared/stories/pack/bundled/tierPack.ts +50 -0
  244. package/src/domains/shared/stories/pack/collectPackStories.test.ts +406 -0
  245. package/src/domains/shared/stories/pack/collectPackStories.ts +158 -0
  246. package/src/domains/shared/stories/pack/compilePackCommands.ts +50 -0
  247. package/src/domains/shared/stories/pack/compilePackStories.test.ts +751 -0
  248. package/src/domains/shared/stories/pack/compilePackStories.ts +724 -0
  249. package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +55 -0
  250. package/src/domains/shared/stories/pack/index.ts +42 -0
  251. package/src/domains/shared/stories/pack/reservedVerbs.test.ts +213 -0
  252. package/src/domains/shared/stories/pack/reservedVerbs.ts +170 -0
  253. package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
  254. package/src/domains/shared/stories/pack/standardParity.test.ts +381 -0
  255. package/src/domains/shared/stories/pack/types.ts +224 -0
  256. package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +742 -0
  257. package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +859 -0
  258. package/src/domains/shared/stories/projectCliParameters.test.ts +59 -0
  259. package/src/domains/shared/stories/projectCliParameters.ts +57 -0
  260. package/src/domains/shared/stories/projectToolParams.test.ts +50 -0
  261. package/src/domains/shared/stories/projectToolParams.ts +32 -0
  262. package/src/domains/shared/stories/requirePragmaContext.test.ts +23 -0
  263. package/src/domains/shared/stories/requirePragmaContext.ts +23 -0
  264. package/src/domains/shared/stories/resolveLookupDetailed.test.ts +57 -0
  265. package/src/domains/shared/stories/resolveLookupDetailed.ts +27 -0
  266. package/src/domains/shared/stories/types.ts +179 -0
  267. package/src/domains/shared/suggestions/expandGlob.ts +1 -0
  268. package/src/domains/shared/suggestions/suggestNames.ts +43 -10
  269. package/src/domains/shared/types/index.ts +5 -9
  270. package/src/domains/shared/types/ontology.ts +119 -24
  271. package/src/domains/shared/types/standard.ts +9 -52
  272. package/src/domains/skill/commands/index.ts +3 -1
  273. package/src/domains/skill/commands/list.test.ts +6 -2
  274. package/src/domains/skill/commands/list.ts +5 -63
  275. package/src/domains/skill/commands/lookup.test.ts +118 -0
  276. package/src/domains/skill/commands/lookup.ts +14 -0
  277. package/src/domains/skill/formatters/index.ts +1 -0
  278. package/src/domains/skill/formatters/lookup.test.ts +46 -0
  279. package/src/domains/skill/formatters/lookup.ts +57 -0
  280. package/src/domains/skill/helpers/resolveSkillSources.ts +0 -1
  281. package/src/domains/skill/index.ts +7 -3
  282. package/src/domains/skill/mcp/specs.ts +10 -29
  283. package/src/domains/skill/operations/discover.test.ts +61 -30
  284. package/src/domains/skill/operations/discover.ts +28 -37
  285. package/src/domains/skill/operations/index.ts +2 -1
  286. package/src/domains/skill/operations/list.test.ts +15 -7
  287. package/src/domains/skill/operations/lookup.test.ts +91 -0
  288. package/src/domains/skill/operations/lookup.ts +70 -0
  289. package/src/domains/skill/stories.test.ts +43 -0
  290. package/src/domains/skill/stories.ts +103 -0
  291. package/src/domains/skill/types.ts +8 -0
  292. package/src/domains/token/commands/lookup.test.ts +8 -0
  293. package/src/domains/token/commands/lookup.ts +12 -0
  294. package/src/domains/token/commands/sample.ts +2 -1
  295. package/src/domains/token/featureFlag.ts +17 -0
  296. package/src/domains/token/index.ts +5 -0
  297. package/src/domains/token/mcp/specs.ts +18 -2
  298. package/src/domains/token/orchestration/resolveTokenLookup.ts +2 -1
  299. package/src/domains/trace/commands/resolveTraceLimit.test.ts +31 -0
  300. package/src/domains/trace/commands/show.ts +30 -4
  301. package/src/domains/trace/tracePlugin.test.ts +1 -1
  302. package/src/index.ts +1 -13
  303. package/src/mcp/registerResources.test.ts +382 -74
  304. package/src/mcp/registerResources.ts +5 -348
  305. package/src/mcp/resources/buildGraphIndex.ts +167 -0
  306. package/src/mcp/resources/buildResourceList.test.ts +97 -0
  307. package/src/mcp/resources/buildResourceList.ts +176 -0
  308. package/src/mcp/resources/classifyEntity.test.ts +40 -0
  309. package/src/mcp/resources/classifyEntity.ts +27 -0
  310. package/src/mcp/resources/constants.ts +105 -0
  311. package/src/mcp/resources/displayPredicates.ts +62 -0
  312. package/src/mcp/resources/pickFirstValue.test.ts +29 -0
  313. package/src/mcp/resources/pickFirstValue.ts +26 -0
  314. package/src/mcp/resources/pickPrimaryType.test.ts +41 -0
  315. package/src/mcp/resources/pickPrimaryType.ts +26 -0
  316. package/src/mcp/resources/rankUriCompletions.test.ts +52 -0
  317. package/src/mcp/resources/rankUriCompletions.ts +64 -0
  318. package/src/mcp/resources/readEntity.ts +169 -0
  319. package/src/mcp/resources/registerResources.ts +126 -0
  320. package/src/mcp/resources/types.ts +128 -0
  321. package/src/mcp/tools/index.ts +22 -5
  322. package/src/mcp/tools/registerTools.test.ts +167 -34
  323. package/src/mcp/types.ts +4 -0
  324. package/src/pipeline/collectCommands.test.ts +151 -1
  325. package/src/pipeline/collectCommands.ts +35 -13
  326. package/src/pipeline/createProgram.test.ts +5 -1
  327. package/src/pipeline/createProgram.ts +2 -2
  328. package/src/pipeline/firstRun.test.ts +80 -0
  329. package/src/pipeline/firstRun.ts +99 -0
  330. package/src/pipeline/parseGlobalFlags.test.ts +102 -1
  331. package/src/pipeline/parseGlobalFlags.ts +98 -9
  332. package/src/pipeline/resolveCommandKind.test.ts +12 -0
  333. package/src/pipeline/resolveCommandKind.ts +4 -0
  334. package/src/pipeline/rootHelp.test.ts +87 -0
  335. package/src/pipeline/rootHelp.ts +265 -0
  336. package/src/pipeline/runCli.orchestration.test.ts +28 -12
  337. package/src/pipeline/runCli.test.ts +17 -4
  338. package/src/pipeline/runCli.ts +202 -25
  339. package/src/testing/cli.ts +30 -2
  340. package/src/testing/createTestMcpClient.ts +4 -1
  341. package/src/testing/dsFixtures.ts +21 -4
  342. package/src/testing/index.ts +7 -0
  343. package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
  344. package/src/testing/integration/cli-user-stories.test.ts +63 -0
  345. package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
  346. package/src/testing/integration/edge-cases.test.ts +62 -50
  347. package/src/testing/integration/executor-execution.test.ts +103 -0
  348. package/src/testing/integration/executor-golden.test.ts +145 -0
  349. package/src/testing/integration/mcp-surface.test.ts +40 -15
  350. package/src/testing/integration/parity.test.ts +136 -82
  351. package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
  352. package/src/testing/setupXdgIsolation.ts +26 -0
  353. package/src/testing/standardParityFixtures.ts +35 -0
  354. package/src/testing/store.ts +4 -4
  355. package/src/testing/storyFixtures.ts +63 -0
  356. package/src/domains/create/commands/component.test.ts +0 -166
  357. package/src/domains/create/commands/component.ts +0 -123
  358. package/src/domains/create/commands/index.ts +0 -3
  359. package/src/domains/create/commands/package.test.ts +0 -35
  360. package/src/domains/create/commands/package.ts +0 -21
  361. package/src/domains/create/generators.ts +0 -8
  362. package/src/domains/standard/commands/categories.test.ts +0 -70
  363. package/src/domains/standard/commands/categories.ts +0 -48
  364. package/src/domains/standard/commands/index.ts +0 -6
  365. package/src/domains/standard/commands/list.test.ts +0 -105
  366. package/src/domains/standard/commands/list.ts +0 -90
  367. package/src/domains/standard/commands/lookup.test.ts +0 -135
  368. package/src/domains/standard/commands/lookup.ts +0 -99
  369. package/src/domains/standard/commands/sample.ts +0 -57
  370. package/src/domains/standard/formatters/categories.test.ts +0 -44
  371. package/src/domains/standard/formatters/categories.ts +0 -38
  372. package/src/domains/standard/formatters/index.ts +0 -10
  373. package/src/domains/standard/formatters/list.test.ts +0 -169
  374. package/src/domains/standard/formatters/list.ts +0 -184
  375. package/src/domains/standard/formatters/lookup.test.ts +0 -95
  376. package/src/domains/standard/formatters/lookup.ts +0 -101
  377. package/src/domains/standard/formatters/sample.ts +0 -15
  378. package/src/domains/standard/formatters/types.ts +0 -31
  379. package/src/domains/standard/index.ts +0 -40
  380. package/src/domains/standard/mcp/index.ts +0 -2
  381. package/src/domains/standard/mcp/specs.ts +0 -244
  382. package/src/domains/standard/operations/categories.test.ts +0 -61
  383. package/src/domains/standard/operations/categories.ts +0 -38
  384. package/src/domains/standard/operations/index.ts +0 -6
  385. package/src/domains/standard/operations/list.test.ts +0 -75
  386. package/src/domains/standard/operations/list.ts +0 -64
  387. package/src/domains/standard/operations/lookup.test.ts +0 -58
  388. package/src/domains/standard/operations/lookup.ts +0 -151
  389. package/src/domains/standard/operations/sample.ts +0 -35
  390. package/src/domains/standard/orchestration/buildStandardFilters.ts +0 -11
  391. package/src/domains/standard/orchestration/index.ts +0 -4
  392. package/src/domains/standard/orchestration/resolveStandardList.ts +0 -45
  393. package/src/domains/standard/orchestration/resolveStandardLookup.ts +0 -32
  394. package/src/domains/standard/orchestration/standardEmptyError.test.ts +0 -33
  395. package/src/domains/standard/orchestration/standardEmptyError.ts +0 -29
  396. package/src/domains/standard/standardConfig.ts +0 -42
  397. package/src/domains/standard/types.ts +0 -15
  398. package/src/domains/tier/commands/index.ts +0 -3
  399. package/src/domains/tier/commands/list.test.ts +0 -67
  400. package/src/domains/tier/commands/list.ts +0 -59
  401. package/src/domains/tier/formatters/index.ts +0 -3
  402. package/src/domains/tier/formatters/list.test.ts +0 -33
  403. package/src/domains/tier/formatters/list.ts +0 -45
  404. package/src/domains/tier/index.ts +0 -17
  405. package/src/domains/tier/mcp/index.ts +0 -2
  406. package/src/domains/tier/mcp/specs.ts +0 -38
  407. package/src/domains/tier/operations/index.ts +0 -3
  408. package/src/domains/tier/operations/list.test.ts +0 -32
  409. package/src/domains/tier/operations/list.ts +0 -33
  410. package/src/pipeline/runInteractiveCommand.ts +0 -198
@@ -0,0 +1,46 @@
1
+ import type { ParameterDefinition } from "@canonical/cli-core";
2
+ import { PragmaError } from "#error";
3
+ import type { ConfigScope } from "../../../config/index.js";
4
+
5
+ /**
6
+ * The `--global` / `--local` target-layer flags shared by every config
7
+ * write command. Without either flag the write follows the global-first
8
+ * rule: nearest existing project file, else the global XDG file.
9
+ */
10
+ export const SCOPE_PARAMETERS: readonly ParameterDefinition[] = [
11
+ {
12
+ name: "global",
13
+ description:
14
+ "Write to the global config ($XDG_CONFIG_HOME/pragma/config.json, default ~/.config/pragma/config.json)",
15
+ type: "boolean",
16
+ default: false,
17
+ },
18
+ {
19
+ name: "local",
20
+ description: "Write to ./pragma.config.json in the current directory",
21
+ type: "boolean",
22
+ default: false,
23
+ },
24
+ ];
25
+
26
+ /**
27
+ * Resolve the explicit write scope from parsed command parameters.
28
+ *
29
+ * @param params - Parsed command parameters.
30
+ * @returns The explicit scope, or `undefined` for the default rule.
31
+ * @throws PragmaError with code `INVALID_INPUT` when both flags are set.
32
+ */
33
+ export function resolveConfigScope(
34
+ params: Record<string, unknown>,
35
+ ): ConfigScope | undefined {
36
+ const global = params.global === true;
37
+ const local = params.local === true;
38
+ if (global && local) {
39
+ throw PragmaError.invalidInput("scope", "--global --local", {
40
+ recovery: { message: "Pass at most one of --global or --local." },
41
+ });
42
+ }
43
+ if (global) return "global";
44
+ if (local) return "local";
45
+ return undefined;
46
+ }
@@ -1,4 +1,10 @@
1
- import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
1
+ import {
2
+ mkdirSync,
3
+ mkdtempSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
2
8
  import { tmpdir } from "node:os";
3
9
  import { join } from "node:path";
4
10
  import type { Store } from "@canonical/ke";
@@ -18,13 +24,24 @@ function makeCtx(cwd: string): PragmaContext {
18
24
 
19
25
  describe("config framework command", () => {
20
26
  let dir: string;
27
+ let xdgDir: string;
28
+ let originalXdg: string | undefined;
21
29
 
22
30
  beforeEach(() => {
23
31
  dir = mkdtempSync(join(tmpdir(), "pragma-cmd-framework-"));
32
+ // Bound the config walk at the fixture root, seed an empty project
33
+ // file so writes stay local, and isolate the global XDG layer.
34
+ mkdirSync(join(dir, ".git"));
35
+ writeFileSync(join(dir, "pragma.config.json"), "{}");
36
+ originalXdg = process.env.XDG_CONFIG_HOME;
37
+ xdgDir = mkdtempSync(join(tmpdir(), "pragma-cmd-framework-xdg-"));
38
+ process.env.XDG_CONFIG_HOME = xdgDir;
24
39
  });
25
40
 
26
41
  afterEach(() => {
42
+ process.env.XDG_CONFIG_HOME = originalXdg;
27
43
  rmSync(dir, { recursive: true, force: true });
44
+ rmSync(xdgDir, { recursive: true, force: true });
28
45
  });
29
46
 
30
47
  it("sets framework to react", async () => {
@@ -45,6 +62,20 @@ describe("config framework command", () => {
45
62
  expect(readConfig(dir).framework).toBe("lit");
46
63
  });
47
64
 
65
+ it("rejects a value combined with --reset", async () => {
66
+ const ctx = makeCtx(dir);
67
+ await expect(
68
+ buildFrameworkCommand(ctx).execute({ value: "react", reset: true }, ctx),
69
+ ).rejects.toMatchObject({ code: "INVALID_INPUT" });
70
+ });
71
+
72
+ it("rejects an explicit empty-string value", async () => {
73
+ const ctx = makeCtx(dir);
74
+ await expect(
75
+ buildFrameworkCommand(ctx).execute({ value: "" }, ctx),
76
+ ).rejects.toMatchObject({ code: "INVALID_INPUT" });
77
+ });
78
+
48
79
  it("rejects an invalid framework", async () => {
49
80
  const ctx = makeCtx(dir);
50
81
  await expect(
@@ -3,13 +3,15 @@ import {
3
3
  type CommandResult,
4
4
  createOutputResult,
5
5
  } from "@canonical/cli-core";
6
- import { runTask } from "@canonical/task";
6
+ import { runTask } from "@canonical/task/node";
7
7
  import { readConfig } from "#config";
8
+ import { PragmaError } from "#error";
8
9
  import type { PragmaContext } from "../../shared/context.js";
9
10
  import { selectFormatter } from "../../shared/formatters.js";
10
11
  import { frameworkFormatters } from "../formatters/index.js";
11
12
  import { validateFramework } from "../operations/index.js";
12
13
  import { setFrameworkTask } from "../tasks/index.js";
14
+ import { resolveConfigScope, SCOPE_PARAMETERS } from "./configScope.js";
13
15
 
14
16
  /**
15
17
  * Build the `pragma config framework` command definition.
@@ -41,6 +43,7 @@ export default function buildFrameworkCommand(
41
43
  type: "boolean",
42
44
  default: false,
43
45
  },
46
+ ...SCOPE_PARAMETERS,
44
47
  ],
45
48
  meta: {
46
49
  examples: [
@@ -53,18 +56,33 @@ export default function buildFrameworkCommand(
53
56
  execute: async (
54
57
  params: Record<string, unknown>,
55
58
  ): Promise<CommandResult> => {
59
+ const scope = resolveConfigScope(params);
56
60
  const reset = params.reset === true;
57
61
  const value = params.value as string | undefined;
58
62
 
63
+ // Contradictory input: a value AND --reset. Reject rather than silently
64
+ // letting one win.
65
+ if (reset && value !== undefined) {
66
+ throw PragmaError.invalidInput("framework", value, {
67
+ recovery: {
68
+ message: "Pass either a framework value or --reset, not both.",
69
+ },
70
+ });
71
+ }
72
+
59
73
  if (reset) {
60
- await runTask(setFrameworkTask(ctx.cwd, undefined));
74
+ const result = await runTask(
75
+ setFrameworkTask(ctx.cwd, undefined, scope),
76
+ );
61
77
  const format = selectFormatter(ctx, frameworkFormatters.reset);
62
- return createOutputResult("Reset framework to default.", {
63
- plain: format,
64
- });
78
+ return createOutputResult(
79
+ { field: "framework", path: result.path },
80
+ { plain: format },
81
+ );
65
82
  }
66
83
 
67
- if (!value) {
84
+ // No value at all → query. An explicit empty string is invalid input.
85
+ if (value === undefined) {
68
86
  const config = readConfig(ctx.cwd);
69
87
  const format = selectFormatter(ctx, frameworkFormatters.query);
70
88
  return createOutputResult(config.framework ?? "none", {
@@ -74,10 +92,10 @@ export default function buildFrameworkCommand(
74
92
 
75
93
  const framework = validateFramework(value);
76
94
 
77
- await runTask(setFrameworkTask(ctx.cwd, framework));
95
+ const result = await runTask(setFrameworkTask(ctx.cwd, framework, scope));
78
96
  const format = selectFormatter(ctx, frameworkFormatters.set);
79
97
  return createOutputResult(
80
- { field: "framework", value: framework },
98
+ { field: "framework", value: framework, path: result.path },
81
99
  { plain: format },
82
100
  );
83
101
  },
@@ -1,51 +1,11 @@
1
- import {
2
- type CommandDefinition,
3
- type CommandResult,
4
- createOutputResult,
5
- } from "@canonical/cli-core";
6
- import { configExists, readConfig, resolveConfigPath } from "#config";
7
- import { detectInstallSource } from "#package-manager";
1
+ import type { CommandDefinition } from "@canonical/cli-core";
8
2
  import type { PragmaContext } from "../../shared/context.js";
9
- import { selectFormatter } from "../../shared/formatters.js";
10
- import { showFormatters } from "../formatters/index.js";
11
- import { resolveConfigShow } from "../operations/index.js";
3
+ import { compileReadCommand } from "../../shared/stories/index.js";
4
+ import { configShowStory } from "../stories.js";
12
5
 
13
- /**
14
- * Build the `pragma config show` command definition.
15
- *
16
- * Displays the resolved configuration including tier, channel,
17
- * package manager, and config file location.
18
- *
19
- * @param ctx - Pragma context providing cwd and formatter selection.
20
- * @returns The command definition for `pragma config show`.
21
- * @note Impure
22
- */
6
+ /** Wire the `pragma config show` CLI command from the config show story. */
23
7
  export default function buildShowCommand(
24
8
  ctx: PragmaContext,
25
9
  ): CommandDefinition {
26
- return {
27
- path: ["config", "show"],
28
- description: "Display resolved configuration",
29
- parameters: [],
30
- meta: {
31
- examples: ["pragma config show"],
32
- },
33
- execute: async (): Promise<CommandResult> => {
34
- const config = readConfig(ctx.cwd);
35
- const install = detectInstallSource();
36
- const cfgPath = resolveConfigPath(ctx.cwd);
37
- const cfgExists = configExists(ctx.cwd);
38
-
39
- const data = resolveConfigShow(config, {
40
- packageManager: install.packageManager,
41
- installSource: install.label,
42
- configFilePath: cfgPath,
43
- configFileExists: cfgExists,
44
- });
45
-
46
- return createOutputResult(data, {
47
- plain: selectFormatter(ctx, showFormatters),
48
- });
49
- },
50
- };
10
+ return compileReadCommand(ctx, configShowStory);
51
11
  }
@@ -1,4 +1,4 @@
1
- import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import type { Store } from "@canonical/ke";
@@ -18,13 +18,24 @@ function makeCtx(cwd: string): PragmaContext {
18
18
 
19
19
  describe("config tier command", () => {
20
20
  let dir: string;
21
+ let xdgDir: string;
22
+ let originalXdg: string | undefined;
21
23
 
22
24
  beforeEach(() => {
23
25
  dir = mkdtempSync(join(tmpdir(), "pragma-cmd-tier-"));
26
+ // Bound the config walk at the fixture root, seed an empty project
27
+ // file so writes stay local, and isolate the global XDG layer.
28
+ mkdirSync(join(dir, ".git"));
29
+ writeFileSync(join(dir, "pragma.config.json"), "{}");
30
+ originalXdg = process.env.XDG_CONFIG_HOME;
31
+ xdgDir = mkdtempSync(join(tmpdir(), "pragma-cmd-tier-xdg-"));
32
+ process.env.XDG_CONFIG_HOME = xdgDir;
24
33
  });
25
34
 
26
35
  afterEach(() => {
36
+ process.env.XDG_CONFIG_HOME = originalXdg;
27
37
  rmSync(dir, { recursive: true, force: true });
38
+ rmSync(xdgDir, { recursive: true, force: true });
28
39
  });
29
40
 
30
41
  it("resets tier via --reset flag", async () => {
@@ -51,7 +62,7 @@ describe("config tier command", () => {
51
62
  expect(result.tag).toBe("output");
52
63
  if (result.tag === "output") {
53
64
  const text = result.render.plain(result.value);
54
- expect(text).toBe("Reset tier to default.");
65
+ expect(text).toContain("Reset tier to default.");
55
66
  }
56
67
  });
57
68
 
@@ -81,4 +92,11 @@ describe("config tier command", () => {
81
92
  expect(text).toBe("No tier set (all tiers visible).");
82
93
  }
83
94
  });
95
+
96
+ it("rejects a tier path combined with --reset", async () => {
97
+ const ctx = makeCtx(dir);
98
+ await expect(
99
+ buildTierCommand(ctx).execute({ path: "apps/lxd", reset: true }, ctx),
100
+ ).rejects.toMatchObject({ code: "INVALID_INPUT" });
101
+ });
84
102
  });
@@ -3,13 +3,15 @@ import {
3
3
  type CommandResult,
4
4
  createOutputResult,
5
5
  } from "@canonical/cli-core";
6
- import { runTask } from "@canonical/task";
6
+ import { runTask } from "@canonical/task/node";
7
7
  import { readConfig } from "#config";
8
+ import { PragmaError } from "#error";
8
9
  import type { PragmaContext } from "../../shared/context.js";
9
10
  import { selectFormatter } from "../../shared/formatters.js";
10
11
  import { tierFormatters } from "../formatters/index.js";
11
12
  import { validateTier } from "../operations/index.js";
12
13
  import { setTierTask } from "../tasks/index.js";
14
+ import { resolveConfigScope, SCOPE_PARAMETERS } from "./configScope.js";
13
15
 
14
16
  /**
15
17
  * Build the `pragma config tier` command definition.
@@ -40,6 +42,7 @@ export default function buildTierCommand(
40
42
  type: "boolean",
41
43
  default: false,
42
44
  },
45
+ ...SCOPE_PARAMETERS,
43
46
  ],
44
47
  meta: {
45
48
  examples: ["pragma config tier apps/lxd", "pragma config tier --reset"],
@@ -47,18 +50,32 @@ export default function buildTierCommand(
47
50
  execute: async (
48
51
  params: Record<string, unknown>,
49
52
  ): Promise<CommandResult> => {
53
+ const scope = resolveConfigScope(params);
50
54
  const reset = params.reset === true;
51
55
  const tierPath = params.path as string | undefined;
52
56
 
57
+ // Contradictory input: a tier path AND --reset. Reject rather than
58
+ // silently letting one win.
59
+ if (reset && tierPath !== undefined) {
60
+ throw PragmaError.invalidInput("tier", tierPath, {
61
+ recovery: {
62
+ message: "Pass either a tier path or --reset, not both.",
63
+ },
64
+ });
65
+ }
66
+
53
67
  if (reset) {
54
- await runTask(setTierTask(ctx.cwd, undefined));
68
+ const result = await runTask(setTierTask(ctx.cwd, undefined, scope));
55
69
  const format = selectFormatter(ctx, tierFormatters.reset);
56
- return createOutputResult("Reset tier to default.", {
57
- plain: format,
58
- });
70
+ return createOutputResult(
71
+ { field: "tier", path: result.path },
72
+ { plain: format },
73
+ );
59
74
  }
60
75
 
61
- if (!tierPath) {
76
+ // No path at all → query. An explicit empty string is invalid input and
77
+ // is rejected by validateTier below.
78
+ if (tierPath === undefined) {
62
79
  const config = readConfig(ctx.cwd);
63
80
  const format = selectFormatter(ctx, tierFormatters.query);
64
81
  return createOutputResult(config.tier, {
@@ -69,10 +86,10 @@ export default function buildTierCommand(
69
86
  // Validate tier against ontology
70
87
  await validateTier(ctx.store, tierPath);
71
88
 
72
- await runTask(setTierTask(ctx.cwd, tierPath));
89
+ const result = await runTask(setTierTask(ctx.cwd, tierPath, scope));
73
90
  const format = selectFormatter(ctx, tierFormatters.set);
74
91
  return createOutputResult(
75
- { field: "tier", value: tierPath },
92
+ { field: "tier", value: tierPath, path: result.path },
76
93
  { plain: format },
77
94
  );
78
95
  },
@@ -1,4 +1,10 @@
1
- import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
1
+ import {
2
+ mkdirSync,
3
+ mkdtempSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
2
8
  import { tmpdir } from "node:os";
3
9
  import { join } from "node:path";
4
10
  import type { Store } from "@canonical/ke";
@@ -18,13 +24,24 @@ function makeCtx(cwd: string): PragmaContext {
18
24
 
19
25
  describe("config trace command", () => {
20
26
  let dir: string;
27
+ let xdgDir: string;
28
+ let originalXdg: string | undefined;
21
29
 
22
30
  beforeEach(() => {
23
31
  dir = mkdtempSync(join(tmpdir(), "pragma-cmd-trace-"));
32
+ // Bound the config walk at the fixture root, seed an empty project
33
+ // file so writes stay local, and isolate the global XDG layer.
34
+ mkdirSync(join(dir, ".git"));
35
+ writeFileSync(join(dir, "pragma.config.json"), "{}");
36
+ originalXdg = process.env.XDG_CONFIG_HOME;
37
+ xdgDir = mkdtempSync(join(tmpdir(), "pragma-cmd-trace-xdg-"));
38
+ process.env.XDG_CONFIG_HOME = xdgDir;
24
39
  });
25
40
 
26
41
  afterEach(() => {
42
+ process.env.XDG_CONFIG_HOME = originalXdg;
27
43
  rmSync(dir, { recursive: true, force: true });
44
+ rmSync(xdgDir, { recursive: true, force: true });
28
45
  });
29
46
 
30
47
  it("enables tracing", async () => {
@@ -54,7 +71,7 @@ describe("config trace command", () => {
54
71
 
55
72
  expect(result.tag).toBe("output");
56
73
  if (result.tag === "output") {
57
- expect(result.render.plain(result.value)).toBe("Tracing enabled.");
74
+ expect(result.render.plain(result.value)).toContain("Tracing enabled.");
58
75
  }
59
76
  });
60
77
 
@@ -3,13 +3,14 @@ import {
3
3
  type CommandResult,
4
4
  createOutputResult,
5
5
  } from "@canonical/cli-core";
6
- import { runTask } from "@canonical/task";
6
+ import { runTask } from "@canonical/task/node";
7
7
  import { readConfig } from "#config";
8
8
  import { PragmaError } from "#error";
9
9
  import type { PragmaContext } from "../../shared/context.js";
10
10
  import { selectFormatter } from "../../shared/formatters.js";
11
11
  import { traceFormatters } from "../formatters/index.js";
12
12
  import { setTraceTask } from "../tasks/index.js";
13
+ import { resolveConfigScope, SCOPE_PARAMETERS } from "./configScope.js";
13
14
 
14
15
  /**
15
16
  * Build the `pragma config trace` command definition.
@@ -30,6 +31,7 @@ export default function buildTraceCommand(
30
31
  type: "string",
31
32
  positional: true,
32
33
  },
34
+ ...SCOPE_PARAMETERS,
33
35
  ],
34
36
  meta: {
35
37
  examples: [
@@ -43,6 +45,7 @@ export default function buildTraceCommand(
43
45
  execute: async (
44
46
  params: Record<string, unknown>,
45
47
  ): Promise<CommandResult> => {
48
+ const scope = resolveConfigScope(params);
46
49
  const value = params.value as string | undefined;
47
50
 
48
51
  // Query mode — no argument
@@ -68,11 +71,11 @@ export default function buildTraceCommand(
68
71
 
69
72
  // Set mode
70
73
  const enabled = value === "on";
71
- await runTask(setTraceTask(ctx.cwd, enabled));
74
+ const result = await runTask(setTraceTask(ctx.cwd, enabled, scope));
72
75
 
73
76
  const format = selectFormatter(ctx, traceFormatters.set);
74
77
  return createOutputResult(
75
- { field: "trace", value: enabled },
78
+ { field: "trace", value: enabled, path: result.path },
76
79
  { plain: format },
77
80
  );
78
81
  },
@@ -2,14 +2,22 @@ import { describe, expect, it } from "vitest";
2
2
  import formatters from "./channel.js";
3
3
 
4
4
  describe("channelFormatters.set", () => {
5
- const data = { field: "channel", value: "experimental" };
5
+ const data = {
6
+ field: "channel",
7
+ value: "experimental",
8
+ path: "/repo/pragma.config.json",
9
+ };
6
10
 
7
11
  it("plain renders set message", () => {
8
- expect(formatters.set.plain(data)).toBe('Set channel to "experimental".');
12
+ expect(formatters.set.plain(data)).toBe(
13
+ 'Set channel to "experimental".\nWrote /repo/pragma.config.json',
14
+ );
9
15
  });
10
16
 
11
17
  it("llm renders set message", () => {
12
- expect(formatters.set.llm(data)).toBe('Set channel to "experimental".');
18
+ expect(formatters.set.llm(data)).toBe(
19
+ 'Set channel to "experimental".\nWrote /repo/pragma.config.json',
20
+ );
13
21
  });
14
22
 
15
23
  it("json returns valid JSON", () => {
@@ -21,15 +29,21 @@ describe("channelFormatters.set", () => {
21
29
 
22
30
  describe("channelFormatters.reset", () => {
23
31
  it("plain renders reset message", () => {
24
- expect(formatters.reset.plain("")).toBe("Reset channel to default.");
32
+ expect(
33
+ formatters.reset.plain({ field: "channel", path: "/repo/p.json" }),
34
+ ).toBe("Reset channel to default.\nWrote /repo/p.json");
25
35
  });
26
36
 
27
37
  it("llm renders reset message", () => {
28
- expect(formatters.reset.llm("")).toBe("Reset channel to default.");
38
+ expect(
39
+ formatters.reset.llm({ field: "channel", path: "/repo/p.json" }),
40
+ ).toBe("Reset channel to default.\nWrote /repo/p.json");
29
41
  });
30
42
 
31
43
  it("json returns valid JSON", () => {
32
- const parsed = JSON.parse(formatters.reset.json(""));
44
+ const parsed = JSON.parse(
45
+ formatters.reset.json({ field: "channel", path: "/repo/p.json" }),
46
+ );
33
47
  expect(parsed.field).toBe("channel");
34
48
  expect(parsed.reset).toBe(true);
35
49
  });
@@ -9,19 +9,22 @@ import type { Formatters } from "../../shared/formatters.js";
9
9
  */
10
10
  const channelFormatters = {
11
11
  set: {
12
- plain: (d: { field: string; value: string }) =>
13
- `Set ${d.field} to "${d.value}".`,
14
- llm: (d: { field: string; value: string }) =>
15
- `Set ${d.field} to "${d.value}".`,
16
- json: (d: { field: string; value: string }) =>
17
- JSON.stringify({ field: d.field, value: d.value }),
18
- } satisfies Formatters<{ field: string; value: string }>,
12
+ plain: (d: { field: string; value: string; path: string }) =>
13
+ `Set ${d.field} to "${d.value}".\nWrote ${d.path}`,
14
+ llm: (d: { field: string; value: string; path: string }) =>
15
+ `Set ${d.field} to "${d.value}".\nWrote ${d.path}`,
16
+ json: (d: { field: string; value: string; path: string }) =>
17
+ JSON.stringify({ field: d.field, value: d.value, path: d.path }),
18
+ } satisfies Formatters<{ field: string; value: string; path: string }>,
19
19
 
20
20
  reset: {
21
- plain: () => "Reset channel to default.",
22
- llm: () => "Reset channel to default.",
23
- json: () => JSON.stringify({ field: "channel", reset: true }),
24
- } satisfies Formatters<string>,
21
+ plain: (d: { field: string; path: string }) =>
22
+ `Reset channel to default.\nWrote ${d.path}`,
23
+ llm: (d: { field: string; path: string }) =>
24
+ `Reset channel to default.\nWrote ${d.path}`,
25
+ json: (d: { field: string; path: string }) =>
26
+ JSON.stringify({ field: "channel", reset: true, path: d.path }),
27
+ } satisfies Formatters<{ field: string; path: string }>,
25
28
 
26
29
  query: {
27
30
  plain: (channel: string) => `Current channel: ${channel}`,
@@ -9,19 +9,22 @@ import type { Formatters } from "../../shared/formatters.js";
9
9
  */
10
10
  const frameworkFormatters = {
11
11
  set: {
12
- plain: (d: { field: string; value: string }) =>
13
- `Set ${d.field} to "${d.value}".`,
14
- llm: (d: { field: string; value: string }) =>
15
- `Set ${d.field} to "${d.value}".`,
16
- json: (d: { field: string; value: string }) =>
17
- JSON.stringify({ field: d.field, value: d.value }),
18
- } satisfies Formatters<{ field: string; value: string }>,
12
+ plain: (d: { field: string; value: string; path: string }) =>
13
+ `Set ${d.field} to "${d.value}".\nWrote ${d.path}`,
14
+ llm: (d: { field: string; value: string; path: string }) =>
15
+ `Set ${d.field} to "${d.value}".\nWrote ${d.path}`,
16
+ json: (d: { field: string; value: string; path: string }) =>
17
+ JSON.stringify({ field: d.field, value: d.value, path: d.path }),
18
+ } satisfies Formatters<{ field: string; value: string; path: string }>,
19
19
 
20
20
  reset: {
21
- plain: () => "Reset framework to default.",
22
- llm: () => "Reset framework to default.",
23
- json: () => JSON.stringify({ field: "framework", reset: true }),
24
- } satisfies Formatters<string>,
21
+ plain: (d: { field: string; path: string }) =>
22
+ `Reset framework to default.\nWrote ${d.path}`,
23
+ llm: (d: { field: string; path: string }) =>
24
+ `Reset framework to default.\nWrote ${d.path}`,
25
+ json: (d: { field: string; path: string }) =>
26
+ JSON.stringify({ field: "framework", reset: true, path: d.path }),
27
+ } satisfies Formatters<{ field: string; path: string }>,
25
28
 
26
29
  query: {
27
30
  plain: (framework: string) => `Current framework: ${framework}`,
@@ -11,6 +11,15 @@ const WITH_TIER: ConfigShowData = {
11
11
  installSource: "bun (global)",
12
12
  configFilePath: "/project/pragma.config.json",
13
13
  configFileExists: true,
14
+ globalConfigPath: "/home/u/.config/pragma/config.json",
15
+ globalConfigExists: false,
16
+ origins: {
17
+ tier: "project",
18
+ channel: "project",
19
+ packages: "default",
20
+ trace: "default",
21
+ framework: "default",
22
+ },
14
23
  };
15
24
 
16
25
  const WITHOUT_TIER: ConfigShowData = {
@@ -22,6 +31,15 @@ const WITHOUT_TIER: ConfigShowData = {
22
31
  installSource: "bun (local)",
23
32
  configFilePath: "/project/pragma.config.json",
24
33
  configFileExists: false,
34
+ globalConfigPath: "/home/u/.config/pragma/config.json",
35
+ globalConfigExists: false,
36
+ origins: {
37
+ tier: "project",
38
+ channel: "project",
39
+ packages: "default",
40
+ trace: "default",
41
+ framework: "default",
42
+ },
25
43
  };
26
44
 
27
45
  const PRERELEASE: ConfigShowData = {
@@ -33,6 +51,15 @@ const PRERELEASE: ConfigShowData = {
33
51
  installSource: "pnpm (global)",
34
52
  configFilePath: "/project/pragma.config.json",
35
53
  configFileExists: true,
54
+ globalConfigPath: "/home/u/.config/pragma/config.json",
55
+ globalConfigExists: false,
56
+ origins: {
57
+ tier: "project",
58
+ channel: "project",
59
+ packages: "default",
60
+ trace: "default",
61
+ framework: "default",
62
+ },
36
63
  };
37
64
 
38
65
  describe("formatters.plain", () => {