@canonical/pragma-cli 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (439) hide show
  1. package/README.md +377 -0
  2. package/package.json +78 -0
  3. package/src/bin.test.ts +52 -0
  4. package/src/bin.ts +19 -0
  5. package/src/compile-validation.runner.ts +137 -0
  6. package/src/compile-validation.ts +192 -0
  7. package/src/completions/computeSocketPath.test.ts +26 -0
  8. package/src/completions/computeSocketPath.ts +16 -0
  9. package/src/completions/constants.ts +18 -0
  10. package/src/completions/handleQuery.test.ts +93 -0
  11. package/src/completions/handleQuery.ts +30 -0
  12. package/src/completions/index.ts +14 -0
  13. package/src/completions/queryCompletions.test.ts +100 -0
  14. package/src/completions/queryCompletions.ts +61 -0
  15. package/src/completions/querySocket.test.ts +70 -0
  16. package/src/completions/querySocket.ts +44 -0
  17. package/src/completions/startCompletionsServer.test.ts +74 -0
  18. package/src/completions/startCompletionsServer.ts +75 -0
  19. package/src/completions/startCompletionsServer.unit.test.ts +131 -0
  20. package/src/completions/waitForSocket.test.ts +27 -0
  21. package/src/completions/waitForSocket.ts +27 -0
  22. package/src/config/configExists.ts +14 -0
  23. package/src/config/index.ts +6 -0
  24. package/src/config/readConfig.test.ts +152 -0
  25. package/src/config/readConfig.ts +64 -0
  26. package/src/config/resolveConfigPath.test.ts +20 -0
  27. package/src/config/resolveConfigPath.ts +11 -0
  28. package/src/config/types.ts +26 -0
  29. package/src/config/writeConfig.ts +49 -0
  30. package/src/constants.ts +78 -0
  31. package/src/domains/block/blockConfig.ts +53 -0
  32. package/src/domains/block/commands/index.ts +4 -0
  33. package/src/domains/block/commands/list.test.ts +111 -0
  34. package/src/domains/block/commands/list.ts +69 -0
  35. package/src/domains/block/commands/lookup.test.ts +187 -0
  36. package/src/domains/block/commands/lookup.ts +199 -0
  37. package/src/domains/block/formatters/index.ts +4 -0
  38. package/src/domains/block/formatters/list.test.ts +107 -0
  39. package/src/domains/block/formatters/list.ts +64 -0
  40. package/src/domains/block/formatters/lookup.test.ts +317 -0
  41. package/src/domains/block/formatters/lookup.ts +354 -0
  42. package/src/domains/block/formatters/types.ts +16 -0
  43. package/src/domains/block/helpers/index.ts +4 -0
  44. package/src/domains/block/helpers/resolveAspects.test.ts +64 -0
  45. package/src/domains/block/helpers/resolveAspects.ts +35 -0
  46. package/src/domains/block/index.ts +25 -0
  47. package/src/domains/block/mcp/index.ts +2 -0
  48. package/src/domains/block/mcp/specs.ts +199 -0
  49. package/src/domains/block/operations/index.ts +4 -0
  50. package/src/domains/block/operations/list.test.ts +80 -0
  51. package/src/domains/block/operations/list.ts +72 -0
  52. package/src/domains/block/operations/lookup.test.ts +108 -0
  53. package/src/domains/block/operations/lookup.ts +359 -0
  54. package/src/domains/block/orchestration/blockEmptyError.ts +19 -0
  55. package/src/domains/block/orchestration/buildBlockFilters.ts +12 -0
  56. package/src/domains/block/orchestration/enrichBlocks.ts +37 -0
  57. package/src/domains/block/orchestration/index.ts +5 -0
  58. package/src/domains/block/orchestration/resolveBlockList.ts +39 -0
  59. package/src/domains/block/orchestration/resolveBlockLookup.ts +21 -0
  60. package/src/domains/block/types.ts +30 -0
  61. package/src/domains/config/commands/channel.test.ts +101 -0
  62. package/src/domains/config/commands/channel.ts +80 -0
  63. package/src/domains/config/commands/index.ts +4 -0
  64. package/src/domains/config/commands/show.test.ts +61 -0
  65. package/src/domains/config/commands/show.ts +51 -0
  66. package/src/domains/config/commands/tier.test.ts +84 -0
  67. package/src/domains/config/commands/tier.ts +78 -0
  68. package/src/domains/config/formatters/channel.test.ts +56 -0
  69. package/src/domains/config/formatters/channel.ts +34 -0
  70. package/src/domains/config/formatters/index.ts +4 -0
  71. package/src/domains/config/formatters/show.test.ts +126 -0
  72. package/src/domains/config/formatters/show.ts +66 -0
  73. package/src/domains/config/formatters/tier.test.ts +70 -0
  74. package/src/domains/config/formatters/tier.ts +40 -0
  75. package/src/domains/config/index.ts +23 -0
  76. package/src/domains/config/mcp/index.ts +2 -0
  77. package/src/domains/config/mcp/specs.ts +108 -0
  78. package/src/domains/config/operations/index.ts +5 -0
  79. package/src/domains/config/operations/show.test.ts +60 -0
  80. package/src/domains/config/operations/show.ts +42 -0
  81. package/src/domains/config/operations/types.ts +13 -0
  82. package/src/domains/config/operations/validateChannel.test.ts +36 -0
  83. package/src/domains/config/operations/validateChannel.ts +24 -0
  84. package/src/domains/config/operations/validateTier.test.ts +56 -0
  85. package/src/domains/config/operations/validateTier.ts +35 -0
  86. package/src/domains/create/commands/component.test.ts +166 -0
  87. package/src/domains/create/commands/component.ts +129 -0
  88. package/src/domains/create/commands/index.ts +3 -0
  89. package/src/domains/create/commands/package.test.ts +35 -0
  90. package/src/domains/create/commands/package.ts +21 -0
  91. package/src/domains/create/index.ts +15 -0
  92. package/src/domains/create/mcp/index.ts +2 -0
  93. package/src/domains/create/mcp/specs.ts +174 -0
  94. package/src/domains/doctor/commands/doctor.test.ts +75 -0
  95. package/src/domains/doctor/commands/doctor.ts +43 -0
  96. package/src/domains/doctor/commands/index.ts +2 -0
  97. package/src/domains/doctor/formatters/doctor.test.ts +117 -0
  98. package/src/domains/doctor/formatters/doctor.ts +84 -0
  99. package/src/domains/doctor/formatters/index.ts +2 -0
  100. package/src/domains/doctor/index.ts +9 -0
  101. package/src/domains/doctor/mcp/index.ts +2 -0
  102. package/src/domains/doctor/mcp/specs.ts +88 -0
  103. package/src/domains/doctor/operations/checks/checkConfigFile.ts +28 -0
  104. package/src/domains/doctor/operations/checks/checkKeStore.ts +38 -0
  105. package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +65 -0
  106. package/src/domains/doctor/operations/checks/checkNodeVersion.ts +25 -0
  107. package/src/domains/doctor/operations/checks/checkPragmaVersion.ts +20 -0
  108. package/src/domains/doctor/operations/checks/checkShellCompletions.ts +42 -0
  109. package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +64 -0
  110. package/src/domains/doctor/operations/checks/index.ts +8 -0
  111. package/src/domains/doctor/operations/checks.test.ts +151 -0
  112. package/src/domains/doctor/operations/index.ts +3 -0
  113. package/src/domains/doctor/operations/runChecks.test.ts +89 -0
  114. package/src/domains/doctor/operations/runChecks.ts +38 -0
  115. package/src/domains/doctor/operations/types.ts +20 -0
  116. package/src/domains/graph/commands/index.ts +4 -0
  117. package/src/domains/graph/commands/inspect.test.ts +94 -0
  118. package/src/domains/graph/commands/inspect.ts +63 -0
  119. package/src/domains/graph/commands/query.test.ts +92 -0
  120. package/src/domains/graph/commands/query.ts +60 -0
  121. package/src/domains/graph/formatters/index.ts +4 -0
  122. package/src/domains/graph/formatters/inspect.ts +45 -0
  123. package/src/domains/graph/formatters/query.ts +37 -0
  124. package/src/domains/graph/helpers/index.ts +3 -0
  125. package/src/domains/graph/helpers/resolveUri.ts +70 -0
  126. package/src/domains/graph/index.ts +22 -0
  127. package/src/domains/graph/mcp/index.ts +2 -0
  128. package/src/domains/graph/mcp/specs.ts +82 -0
  129. package/src/domains/graph/operations/executeQuery.test.ts +68 -0
  130. package/src/domains/graph/operations/executeQuery.ts +32 -0
  131. package/src/domains/graph/operations/index.ts +4 -0
  132. package/src/domains/graph/operations/inspectUri.test.ts +101 -0
  133. package/src/domains/graph/operations/inspectUri.ts +61 -0
  134. package/src/domains/info/commands/index.ts +4 -0
  135. package/src/domains/info/commands/info.test.ts +88 -0
  136. package/src/domains/info/commands/info.ts +47 -0
  137. package/src/domains/info/commands/upgrade.test.ts +183 -0
  138. package/src/domains/info/commands/upgrade.ts +150 -0
  139. package/src/domains/info/constants.test.ts +22 -0
  140. package/src/domains/info/constants.ts +15 -0
  141. package/src/domains/info/formatters/index.ts +8 -0
  142. package/src/domains/info/formatters/info.test.ts +173 -0
  143. package/src/domains/info/formatters/info.ts +116 -0
  144. package/src/domains/info/formatters/upgrade.test.ts +133 -0
  145. package/src/domains/info/formatters/upgrade.ts +68 -0
  146. package/src/domains/info/index.ts +7 -0
  147. package/src/domains/info/operations/checkRegistryVersion.test.ts +124 -0
  148. package/src/domains/info/operations/checkRegistryVersion.ts +45 -0
  149. package/src/domains/info/operations/collectInfo.test.ts +111 -0
  150. package/src/domains/info/operations/collectInfo.ts +68 -0
  151. package/src/domains/info/operations/collectStoreSummary.test.ts +61 -0
  152. package/src/domains/info/operations/collectStoreSummary.ts +42 -0
  153. package/src/domains/info/operations/index.ts +5 -0
  154. package/src/domains/info/types.test-d.ts +35 -0
  155. package/src/domains/info/types.ts +46 -0
  156. package/src/domains/llm/commands/index.ts +3 -0
  157. package/src/domains/llm/commands/llm.ts +37 -0
  158. package/src/domains/llm/data/commandReference.ts +25 -0
  159. package/src/domains/llm/data/decisionTrees.ts +46 -0
  160. package/src/domains/llm/data/index.ts +4 -0
  161. package/src/domains/llm/formatters/index.ts +3 -0
  162. package/src/domains/llm/formatters/orientation.ts +53 -0
  163. package/src/domains/llm/index.ts +8 -0
  164. package/src/domains/llm/llmCommand.test.ts +93 -0
  165. package/src/domains/llm/mcp/index.ts +2 -0
  166. package/src/domains/llm/mcp/specs.ts +87 -0
  167. package/src/domains/llm/operations/collectContext.ts +47 -0
  168. package/src/domains/llm/operations/index.ts +3 -0
  169. package/src/domains/llm/types.ts +32 -0
  170. package/src/domains/modifier/commands/index.ts +4 -0
  171. package/src/domains/modifier/commands/list.test.ts +57 -0
  172. package/src/domains/modifier/commands/list.ts +33 -0
  173. package/src/domains/modifier/commands/lookup.test.ts +91 -0
  174. package/src/domains/modifier/commands/lookup.ts +105 -0
  175. package/src/domains/modifier/formatters/index.ts +4 -0
  176. package/src/domains/modifier/formatters/list.test.ts +38 -0
  177. package/src/domains/modifier/formatters/list.ts +35 -0
  178. package/src/domains/modifier/formatters/lookup.test.ts +33 -0
  179. package/src/domains/modifier/formatters/lookup.ts +38 -0
  180. package/src/domains/modifier/index.ts +22 -0
  181. package/src/domains/modifier/mcp/index.ts +2 -0
  182. package/src/domains/modifier/mcp/specs.ts +97 -0
  183. package/src/domains/modifier/operations/index.ts +4 -0
  184. package/src/domains/modifier/operations/list.test.ts +39 -0
  185. package/src/domains/modifier/operations/list.ts +41 -0
  186. package/src/domains/modifier/operations/lookup.test.ts +37 -0
  187. package/src/domains/modifier/operations/lookup.ts +57 -0
  188. package/src/domains/modifier/orchestration/index.ts +3 -0
  189. package/src/domains/modifier/orchestration/modifierEmptyError.ts +10 -0
  190. package/src/domains/modifier/orchestration/resolveModifierList.ts +16 -0
  191. package/src/domains/modifier/orchestration/resolveModifierLookup.ts +20 -0
  192. package/src/domains/modifier/types.ts +5 -0
  193. package/src/domains/ontology/commands/index.ts +4 -0
  194. package/src/domains/ontology/commands/list.test.ts +82 -0
  195. package/src/domains/ontology/commands/list.ts +46 -0
  196. package/src/domains/ontology/commands/show.test.ts +103 -0
  197. package/src/domains/ontology/commands/show.ts +66 -0
  198. package/src/domains/ontology/formatters/index.ts +4 -0
  199. package/src/domains/ontology/formatters/list.ts +37 -0
  200. package/src/domains/ontology/formatters/show.ts +74 -0
  201. package/src/domains/ontology/helpers/findNamespace.ts +23 -0
  202. package/src/domains/ontology/helpers/index.ts +7 -0
  203. package/src/domains/ontology/helpers/queryClasses.ts +50 -0
  204. package/src/domains/ontology/helpers/queryProperties.ts +57 -0
  205. package/src/domains/ontology/helpers/resolvePrefix.ts +45 -0
  206. package/src/domains/ontology/index.ts +26 -0
  207. package/src/domains/ontology/mcp/index.ts +2 -0
  208. package/src/domains/ontology/mcp/specs.ts +93 -0
  209. package/src/domains/ontology/operations/index.ts +5 -0
  210. package/src/domains/ontology/operations/listOntologies.test.ts +45 -0
  211. package/src/domains/ontology/operations/listOntologies.ts +101 -0
  212. package/src/domains/ontology/operations/showOntology.test.ts +65 -0
  213. package/src/domains/ontology/operations/showOntology.ts +41 -0
  214. package/src/domains/ontology/operations/showOntologyRaw.test.ts +39 -0
  215. package/src/domains/ontology/operations/showOntologyRaw.ts +50 -0
  216. package/src/domains/setup/commands/all.ts +58 -0
  217. package/src/domains/setup/commands/completions.ts +85 -0
  218. package/src/domains/setup/commands/entrypoints.test.ts +170 -0
  219. package/src/domains/setup/commands/index.ts +6 -0
  220. package/src/domains/setup/commands/lsp.ts +49 -0
  221. package/src/domains/setup/commands/mcp.ts +119 -0
  222. package/src/domains/setup/commands/skills.test.ts +64 -0
  223. package/src/domains/setup/commands/skills.ts +106 -0
  224. package/src/domains/setup/formatters/index.ts +2 -0
  225. package/src/domains/setup/formatters/skills.test.ts +103 -0
  226. package/src/domains/setup/formatters/skills.ts +112 -0
  227. package/src/domains/setup/formatters/types.ts +7 -0
  228. package/src/domains/setup/helpers/completionScripts.test.ts +58 -0
  229. package/src/domains/setup/helpers/completionScripts.ts +92 -0
  230. package/src/domains/setup/helpers/constants.ts +2 -0
  231. package/src/domains/setup/helpers/detectShell.test.ts +48 -0
  232. package/src/domains/setup/helpers/detectShell.ts +20 -0
  233. package/src/domains/setup/helpers/index.ts +12 -0
  234. package/src/domains/setup/helpers/runSetupTask.test.ts +279 -0
  235. package/src/domains/setup/helpers/runSetupTask.ts +229 -0
  236. package/src/domains/setup/index.ts +33 -0
  237. package/src/domains/setup/operations/index.ts +6 -0
  238. package/src/domains/setup/operations/setupAll.test.ts +48 -0
  239. package/src/domains/setup/operations/setupAll.ts +41 -0
  240. package/src/domains/setup/operations/setupCompletions.test.ts +94 -0
  241. package/src/domains/setup/operations/setupCompletions.ts +54 -0
  242. package/src/domains/setup/operations/setupLsp.test.ts +29 -0
  243. package/src/domains/setup/operations/setupLsp.ts +17 -0
  244. package/src/domains/setup/operations/setupMcp.test.ts +115 -0
  245. package/src/domains/setup/operations/setupMcp.ts +108 -0
  246. package/src/domains/setup/operations/setupSkills.test.ts +191 -0
  247. package/src/domains/setup/operations/setupSkills.ts +160 -0
  248. package/src/domains/setup/types.ts +18 -0
  249. package/src/domains/shared/ToolSpec.ts +49 -0
  250. package/src/domains/shared/bootStore.ts +77 -0
  251. package/src/domains/shared/buildQuery.ts +18 -0
  252. package/src/domains/shared/compactUri.test.ts +21 -0
  253. package/src/domains/shared/compactUri.ts +16 -0
  254. package/src/domains/shared/context.ts +15 -0
  255. package/src/domains/shared/contracts.ts +113 -0
  256. package/src/domains/shared/extractLocalName.test.ts +21 -0
  257. package/src/domains/shared/extractLocalName.ts +14 -0
  258. package/src/domains/shared/filters/buildChannelFilter.test.ts +52 -0
  259. package/src/domains/shared/filters/buildChannelFilter.ts +41 -0
  260. package/src/domains/shared/filters/buildFilterConfig.ts +16 -0
  261. package/src/domains/shared/filters/buildFilters.test.ts +33 -0
  262. package/src/domains/shared/filters/buildFilters.ts +30 -0
  263. package/src/domains/shared/filters/buildTierFilter.test.ts +78 -0
  264. package/src/domains/shared/filters/buildTierFilter.ts +69 -0
  265. package/src/domains/shared/filters/describeFilters.ts +14 -0
  266. package/src/domains/shared/filters/index.ts +10 -0
  267. package/src/domains/shared/formatters.ts +35 -0
  268. package/src/domains/shared/lookupMany.ts +45 -0
  269. package/src/domains/shared/namespaces.ts +18 -0
  270. package/src/domains/shared/packages.ts +76 -0
  271. package/src/domains/shared/prefixes.ts +37 -0
  272. package/src/domains/shared/runtime.ts +62 -0
  273. package/src/domains/shared/types.test-d.ts +127 -0
  274. package/src/domains/shared/types.ts +348 -0
  275. package/src/domains/skill/commands/index.ts +2 -0
  276. package/src/domains/skill/commands/list.test.ts +111 -0
  277. package/src/domains/skill/commands/list.ts +69 -0
  278. package/src/domains/skill/formatters/index.ts +2 -0
  279. package/src/domains/skill/formatters/list.test.ts +140 -0
  280. package/src/domains/skill/formatters/list.ts +119 -0
  281. package/src/domains/skill/formatters/types.ts +8 -0
  282. package/src/domains/skill/helpers/index.ts +6 -0
  283. package/src/domains/skill/helpers/parseFrontmatter.test.ts +122 -0
  284. package/src/domains/skill/helpers/parseFrontmatter.ts +112 -0
  285. package/src/domains/skill/helpers/resolveSkillSources.ts +34 -0
  286. package/src/domains/skill/index.ts +19 -0
  287. package/src/domains/skill/mcp/index.ts +2 -0
  288. package/src/domains/skill/mcp/specs.ts +38 -0
  289. package/src/domains/skill/operations/discover.test.ts +145 -0
  290. package/src/domains/skill/operations/discover.ts +68 -0
  291. package/src/domains/skill/operations/index.ts +4 -0
  292. package/src/domains/skill/operations/list.test.ts +68 -0
  293. package/src/domains/skill/operations/list.ts +47 -0
  294. package/src/domains/skill/types.ts +25 -0
  295. package/src/domains/standard/commands/categories.test.ts +70 -0
  296. package/src/domains/standard/commands/categories.ts +48 -0
  297. package/src/domains/standard/commands/index.ts +5 -0
  298. package/src/domains/standard/commands/list.test.ts +105 -0
  299. package/src/domains/standard/commands/list.ts +81 -0
  300. package/src/domains/standard/commands/lookup.test.ts +135 -0
  301. package/src/domains/standard/commands/lookup.ts +127 -0
  302. package/src/domains/standard/formatters/categories.test.ts +44 -0
  303. package/src/domains/standard/formatters/categories.ts +38 -0
  304. package/src/domains/standard/formatters/index.ts +6 -0
  305. package/src/domains/standard/formatters/list.test.ts +166 -0
  306. package/src/domains/standard/formatters/list.ts +156 -0
  307. package/src/domains/standard/formatters/lookup.test.ts +95 -0
  308. package/src/domains/standard/formatters/lookup.ts +86 -0
  309. package/src/domains/standard/formatters/types.ts +31 -0
  310. package/src/domains/standard/index.ts +32 -0
  311. package/src/domains/standard/mcp/index.ts +2 -0
  312. package/src/domains/standard/mcp/specs.ts +197 -0
  313. package/src/domains/standard/operations/categories.test.ts +61 -0
  314. package/src/domains/standard/operations/categories.ts +38 -0
  315. package/src/domains/standard/operations/index.ts +5 -0
  316. package/src/domains/standard/operations/list.test.ts +75 -0
  317. package/src/domains/standard/operations/list.ts +64 -0
  318. package/src/domains/standard/operations/lookup.test.ts +58 -0
  319. package/src/domains/standard/operations/lookup.ts +142 -0
  320. package/src/domains/standard/orchestration/buildStandardFilters.ts +11 -0
  321. package/src/domains/standard/orchestration/index.ts +4 -0
  322. package/src/domains/standard/orchestration/resolveStandardList.ts +42 -0
  323. package/src/domains/standard/orchestration/resolveStandardLookup.ts +20 -0
  324. package/src/domains/standard/orchestration/standardEmptyError.ts +19 -0
  325. package/src/domains/standard/types.ts +15 -0
  326. package/src/domains/tier/commands/index.ts +3 -0
  327. package/src/domains/tier/commands/list.test.ts +67 -0
  328. package/src/domains/tier/commands/list.ts +43 -0
  329. package/src/domains/tier/formatters/index.ts +3 -0
  330. package/src/domains/tier/formatters/list.test.ts +33 -0
  331. package/src/domains/tier/formatters/list.ts +40 -0
  332. package/src/domains/tier/index.ts +17 -0
  333. package/src/domains/tier/mcp/index.ts +2 -0
  334. package/src/domains/tier/mcp/specs.ts +38 -0
  335. package/src/domains/tier/operations/index.ts +3 -0
  336. package/src/domains/tier/operations/list.test.ts +32 -0
  337. package/src/domains/tier/operations/list.ts +33 -0
  338. package/src/domains/token/commands/add-config.test.ts +68 -0
  339. package/src/domains/token/commands/add-config.ts +62 -0
  340. package/src/domains/token/commands/index.ts +5 -0
  341. package/src/domains/token/commands/list.test.ts +82 -0
  342. package/src/domains/token/commands/list.ts +45 -0
  343. package/src/domains/token/commands/lookup.test.ts +125 -0
  344. package/src/domains/token/commands/lookup.ts +121 -0
  345. package/src/domains/token/formatters/index.ts +4 -0
  346. package/src/domains/token/formatters/list.test.ts +37 -0
  347. package/src/domains/token/formatters/list.ts +37 -0
  348. package/src/domains/token/formatters/lookup.test.ts +61 -0
  349. package/src/domains/token/formatters/lookup.ts +72 -0
  350. package/src/domains/token/index.ts +32 -0
  351. package/src/domains/token/mcp/index.ts +2 -0
  352. package/src/domains/token/mcp/specs.ts +145 -0
  353. package/src/domains/token/operations/add-config.test.ts +68 -0
  354. package/src/domains/token/operations/add-config.ts +61 -0
  355. package/src/domains/token/operations/index.ts +7 -0
  356. package/src/domains/token/operations/list.test.ts +50 -0
  357. package/src/domains/token/operations/list.ts +52 -0
  358. package/src/domains/token/operations/lookup.test.ts +42 -0
  359. package/src/domains/token/operations/lookup.ts +66 -0
  360. package/src/domains/token/orchestration/index.ts +3 -0
  361. package/src/domains/token/orchestration/resolveTokenList.ts +17 -0
  362. package/src/domains/token/orchestration/resolveTokenLookup.ts +20 -0
  363. package/src/domains/token/orchestration/tokenEmptyError.ts +17 -0
  364. package/src/domains/token/types.ts +6 -0
  365. package/src/error/PragmaError.test.ts +121 -0
  366. package/src/error/PragmaError.ts +164 -0
  367. package/src/error/constants.ts +12 -0
  368. package/src/error/index.ts +4 -0
  369. package/src/error/types.ts +41 -0
  370. package/src/index.ts +141 -0
  371. package/src/mcp/createMcpServer.test.ts +41 -0
  372. package/src/mcp/createMcpServer.ts +53 -0
  373. package/src/mcp/error/buildRecovery.test.ts +37 -0
  374. package/src/mcp/error/buildRecovery.ts +17 -0
  375. package/src/mcp/error/index.ts +12 -0
  376. package/src/mcp/error/serializeError.test.ts +121 -0
  377. package/src/mcp/error/serializeError.ts +31 -0
  378. package/src/mcp/error/serializeErrorPayload.test.ts +38 -0
  379. package/src/mcp/error/serializeErrorPayload.ts +27 -0
  380. package/src/mcp/error/types.ts +51 -0
  381. package/src/mcp/index.ts +15 -0
  382. package/src/mcp/registerResources.test.ts +236 -0
  383. package/src/mcp/registerResources.ts +303 -0
  384. package/src/mcp/runMcpServer.test.ts +66 -0
  385. package/src/mcp/runMcpServer.ts +24 -0
  386. package/src/mcp/tools/index.ts +55 -0
  387. package/src/mcp/tools/registerFromSpec.ts +97 -0
  388. package/src/mcp/tools/registerTools.test.ts +1124 -0
  389. package/src/mcp/types.ts +62 -0
  390. package/src/mcp/utils/estimateTokens.test.ts +14 -0
  391. package/src/mcp/utils/estimateTokens.ts +9 -0
  392. package/src/mcp/utils/index.ts +11 -0
  393. package/src/mcp/utils/wrapTool.test.ts +108 -0
  394. package/src/mcp/utils/wrapTool.ts +81 -0
  395. package/src/package-manager/constants.ts +29 -0
  396. package/src/package-manager/detectInstallSource.test.ts +23 -0
  397. package/src/package-manager/detectInstallSource.ts +111 -0
  398. package/src/package-manager/detectLocalInstall.test.ts +16 -0
  399. package/src/package-manager/detectLocalInstall.ts +43 -0
  400. package/src/package-manager/detectPackageManager.test.ts +81 -0
  401. package/src/package-manager/detectPackageManager.ts +30 -0
  402. package/src/package-manager/index.ts +6 -0
  403. package/src/package-manager/types.ts +12 -0
  404. package/src/pipeline/collectCommands.test.ts +37 -0
  405. package/src/pipeline/collectCommands.ts +47 -0
  406. package/src/pipeline/constants.ts +14 -0
  407. package/src/pipeline/createProgram.test.ts +112 -0
  408. package/src/pipeline/createProgram.ts +70 -0
  409. package/src/pipeline/formatTerminal.test.ts +43 -0
  410. package/src/pipeline/formatTerminal.ts +53 -0
  411. package/src/pipeline/index.ts +19 -0
  412. package/src/pipeline/mapExitCode.test.ts +41 -0
  413. package/src/pipeline/mapExitCode.ts +12 -0
  414. package/src/pipeline/parseGlobalFlags.ts +21 -0
  415. package/src/pipeline/renderError.test.ts +151 -0
  416. package/src/pipeline/renderError.ts +114 -0
  417. package/src/pipeline/resolveCommandKind.test.ts +68 -0
  418. package/src/pipeline/resolveCommandKind.ts +71 -0
  419. package/src/pipeline/runCli.orchestration.test.ts +418 -0
  420. package/src/pipeline/runCli.test.ts +70 -0
  421. package/src/pipeline/runCli.ts +215 -0
  422. package/src/pipeline/types.ts +17 -0
  423. package/src/testing/cli.ts +43 -0
  424. package/src/testing/createTestMcpClient.ts +64 -0
  425. package/src/testing/dsFixtures.ts +506 -0
  426. package/src/testing/fixtures/canonical-config.json +4 -0
  427. package/src/testing/fixtures/canonical.ttl +437 -0
  428. package/src/testing/fixtures/filtered-config.json +4 -0
  429. package/src/testing/fixtures.ts +34 -0
  430. package/src/testing/helpers/assertParity.ts +28 -0
  431. package/src/testing/helpers/createTestMcpClient.ts +40 -0
  432. package/src/testing/helpers/createTestRuntime.ts +67 -0
  433. package/src/testing/index.ts +8 -0
  434. package/src/testing/integration/agent-session.test.ts +148 -0
  435. package/src/testing/integration/boot.test.ts +67 -0
  436. package/src/testing/integration/mcp-surface.test.ts +574 -0
  437. package/src/testing/integration/parity.test.ts +192 -0
  438. package/src/testing/store.ts +39 -0
  439. package/src/testing/types.ts +20 -0
@@ -0,0 +1,39 @@
1
+ import type { ListParams } from "../../shared/contracts.js";
2
+ import type { PragmaRuntime } from "../../shared/runtime.js";
3
+ import type { Disclosure } from "../../shared/types.js";
4
+ import { listBlocks } from "../operations/index.js";
5
+ import type { BlockListContract } from "../types.js";
6
+ import blockEmptyError from "./blockEmptyError.js";
7
+ import buildBlockFilters from "./buildBlockFilters.js";
8
+ import enrichBlocks from "./enrichBlocks.js";
9
+
10
+ export default async function resolveBlockList(
11
+ rt: Pick<PragmaRuntime, "store" | "config">,
12
+ params: ListParams,
13
+ ): Promise<BlockListContract> {
14
+ const filters = buildBlockFilters(rt, params.allTiers);
15
+ const disclosure: Disclosure = params.detailed
16
+ ? { level: "detailed" }
17
+ : params.digest
18
+ ? { level: "digest" }
19
+ : { level: "summary" };
20
+ const summaries = await listBlocks(rt.store, filters);
21
+
22
+ if (summaries.length === 0) {
23
+ throw blockEmptyError(filters, params.allTiers);
24
+ }
25
+
26
+ const items =
27
+ disclosure.level === "summary"
28
+ ? summaries
29
+ : await enrichBlocks(summaries, rt.store, filters, disclosure);
30
+
31
+ return {
32
+ params,
33
+ result: {
34
+ items,
35
+ filters,
36
+ disclosure,
37
+ },
38
+ };
39
+ }
@@ -0,0 +1,21 @@
1
+ import type { LookupContract, LookupResult } from "../../shared/contracts.js";
2
+ import lookupMany from "../../shared/lookupMany.js";
3
+ import type { PragmaRuntime } from "../../shared/runtime.js";
4
+ import type { BlockDetailed, FilterConfig } from "../../shared/types.js";
5
+ import { lookupBlock } from "../operations/index.js";
6
+
7
+ export default async function resolveBlockLookup(
8
+ store: Pick<PragmaRuntime, "store">["store"],
9
+ queries: readonly string[],
10
+ filters: FilterConfig,
11
+ ): Promise<LookupContract<BlockDetailed>> {
12
+ const result: LookupResult<BlockDetailed> = await lookupMany(
13
+ queries,
14
+ (query) => lookupBlock(store, query, filters),
15
+ );
16
+
17
+ return {
18
+ params: { names: queries },
19
+ result,
20
+ };
21
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Block domain types.
3
+ *
4
+ * Reused across block commands, formatters, and aspect resolution.
5
+ */
6
+
7
+ import type { ListContract } from "../shared/contracts.js";
8
+ import type { BlockDetailed, BlockSummary } from "../shared/types.js";
9
+
10
+ /** Flags controlling which detail aspects are included in block output. */
11
+ export interface AspectFlags {
12
+ readonly anatomy: boolean;
13
+ readonly modifiers: boolean;
14
+ readonly tokens: boolean;
15
+ readonly implementations: boolean;
16
+ }
17
+
18
+ export interface BlockListDigest extends BlockSummary {
19
+ readonly summary: string | null;
20
+ readonly implementationPaths: readonly {
21
+ framework: string;
22
+ path: string;
23
+ }[];
24
+ }
25
+
26
+ export type BlockListContract = ListContract<
27
+ BlockSummary,
28
+ BlockListDigest,
29
+ BlockDetailed
30
+ >;
@@ -0,0 +1,101 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import type { Store } from "@canonical/ke";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import { readConfig } from "#config";
7
+ import type { PragmaContext } from "../../shared/context.js";
8
+ import buildChannelCommand from "./channel.js";
9
+
10
+ function makeCtx(cwd: string): PragmaContext {
11
+ return {
12
+ cwd,
13
+ globalFlags: { llm: false, format: "text" as const, verbose: false },
14
+ store: {} as Store,
15
+ config: { tier: undefined, channel: "normal" },
16
+ };
17
+ }
18
+
19
+ describe("config channel command", () => {
20
+ let dir: string;
21
+
22
+ beforeEach(() => {
23
+ dir = mkdtempSync(join(tmpdir(), "pragma-cmd-channel-"));
24
+ });
25
+
26
+ afterEach(() => {
27
+ rmSync(dir, { recursive: true, force: true });
28
+ });
29
+
30
+ it("sets channel to experimental", async () => {
31
+ const ctx = makeCtx(dir);
32
+ const cmd = buildChannelCommand(ctx);
33
+ const result = await cmd.execute({ value: "experimental" }, ctx);
34
+
35
+ expect(result.tag).toBe("output");
36
+ const config = readConfig(dir);
37
+ expect(config.channel).toBe("experimental");
38
+ });
39
+
40
+ it("renders set output", async () => {
41
+ const ctx = makeCtx(dir);
42
+ const cmd = buildChannelCommand(ctx);
43
+ const result = await cmd.execute({ value: "prerelease" }, ctx);
44
+
45
+ expect(result.tag).toBe("output");
46
+ if (result.tag === "output") {
47
+ const text = result.render.plain(result.value);
48
+ expect(text).toBe('Set channel to "prerelease".');
49
+ }
50
+ });
51
+
52
+ it("resets channel via --reset flag", async () => {
53
+ writeFileSync(
54
+ join(dir, "pragma.config.json"),
55
+ '{"channel":"experimental"}',
56
+ );
57
+
58
+ const ctx = makeCtx(dir);
59
+ const cmd = buildChannelCommand(ctx);
60
+ const result = await cmd.execute({ reset: true }, ctx);
61
+
62
+ expect(result.tag).toBe("output");
63
+ const config = readConfig(dir);
64
+ expect(config.channel).toBe("normal");
65
+ });
66
+
67
+ it("renders reset output", async () => {
68
+ const ctx = makeCtx(dir);
69
+ const cmd = buildChannelCommand(ctx);
70
+ const result = await cmd.execute({ reset: true }, ctx);
71
+
72
+ expect(result.tag).toBe("output");
73
+ if (result.tag === "output") {
74
+ const text = result.render.plain(result.value);
75
+ expect(text).toBe("Reset channel to default.");
76
+ }
77
+ });
78
+
79
+ it("shows current channel when no args", async () => {
80
+ writeFileSync(join(dir, "pragma.config.json"), '{"channel":"prerelease"}');
81
+
82
+ const ctx = makeCtx(dir);
83
+ const cmd = buildChannelCommand(ctx);
84
+ const result = await cmd.execute({}, ctx);
85
+
86
+ expect(result.tag).toBe("output");
87
+ if (result.tag === "output") {
88
+ expect(result.value).toBe("prerelease");
89
+ const text = result.render.plain(result.value);
90
+ expect(text).toBe("Current channel: prerelease");
91
+ }
92
+ });
93
+
94
+ it("throws INVALID_INPUT for invalid channel", async () => {
95
+ const ctx = makeCtx(dir);
96
+ const cmd = buildChannelCommand(ctx);
97
+ await expect(cmd.execute({ value: "aggressive" }, ctx)).rejects.toThrow(
98
+ 'Invalid channel "aggressive"',
99
+ );
100
+ });
101
+ });
@@ -0,0 +1,80 @@
1
+ import {
2
+ type CommandDefinition,
3
+ type CommandResult,
4
+ createOutputResult,
5
+ } from "@canonical/cli-core";
6
+ import { readConfig, writeConfig } from "#config";
7
+ import type { PragmaContext } from "../../shared/context.js";
8
+ import { selectFormatter } from "../../shared/formatters.js";
9
+ import { channelFormatters } from "../formatters/index.js";
10
+ import { validateChannel } from "../operations/index.js";
11
+
12
+ /**
13
+ * Build the `pragma config channel` command definition.
14
+ *
15
+ * Supports three modes: set a channel value, reset to default, or
16
+ * query the current channel when no arguments are provided.
17
+ *
18
+ * @param ctx - Pragma context providing cwd and formatter selection.
19
+ * @returns The command definition for `pragma config channel`.
20
+ * @note Impure
21
+ */
22
+ export default function buildChannelCommand(
23
+ ctx: PragmaContext,
24
+ ): CommandDefinition {
25
+ return {
26
+ path: ["config", "channel"],
27
+ description: "Set or reset the release channel",
28
+ parameters: [
29
+ {
30
+ name: "value",
31
+ description: "Channel (normal, experimental, prerelease)",
32
+ type: "string",
33
+ positional: true,
34
+ },
35
+ {
36
+ name: "reset",
37
+ description: "Reset channel to normal",
38
+ type: "boolean",
39
+ default: false,
40
+ },
41
+ ],
42
+ meta: {
43
+ examples: [
44
+ "pragma config channel experimental",
45
+ "pragma config channel --reset",
46
+ ],
47
+ },
48
+ execute: async (
49
+ params: Record<string, unknown>,
50
+ ): Promise<CommandResult> => {
51
+ const reset = params.reset === true;
52
+ const value = params.value as string | undefined;
53
+
54
+ if (reset) {
55
+ writeConfig(ctx.cwd, { channel: undefined });
56
+ const format = selectFormatter(ctx, channelFormatters.reset);
57
+ return createOutputResult("Reset channel to default.", {
58
+ plain: format,
59
+ });
60
+ }
61
+
62
+ if (!value) {
63
+ const config = readConfig(ctx.cwd);
64
+ const format = selectFormatter(ctx, channelFormatters.query);
65
+ return createOutputResult(config.channel, {
66
+ plain: format,
67
+ });
68
+ }
69
+
70
+ const channel = validateChannel(value);
71
+
72
+ writeConfig(ctx.cwd, { channel });
73
+ const format = selectFormatter(ctx, channelFormatters.set);
74
+ return createOutputResult(
75
+ { field: "channel", value: channel },
76
+ { plain: format },
77
+ );
78
+ },
79
+ };
80
+ }
@@ -0,0 +1,4 @@
1
+ /** @module Config command definitions for `pragma config`. */
2
+ export { default as channelCommand } from "./channel.js";
3
+ export { default as showCommand } from "./show.js";
4
+ export { default as tierCommand } from "./tier.js";
@@ -0,0 +1,61 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import type { Store } from "@canonical/ke";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import type { PragmaContext } from "../../shared/context.js";
7
+ import buildShowCommand from "./show.js";
8
+
9
+ function makeCtx(cwd: string): PragmaContext {
10
+ return {
11
+ cwd,
12
+ globalFlags: { llm: false, format: "text" as const, verbose: false },
13
+ store: {} as Store,
14
+ config: { tier: undefined, channel: "normal" },
15
+ };
16
+ }
17
+
18
+ describe("config show command", () => {
19
+ let dir: string;
20
+
21
+ beforeEach(() => {
22
+ dir = mkdtempSync(join(tmpdir(), "pragma-cmd-show-"));
23
+ });
24
+
25
+ afterEach(() => {
26
+ rmSync(dir, { recursive: true, force: true });
27
+ });
28
+
29
+ it("renders show output with defaults", async () => {
30
+ const ctx = makeCtx(dir);
31
+ const cmd = buildShowCommand(ctx);
32
+ const result = await cmd.execute({}, ctx);
33
+
34
+ expect(result.tag).toBe("output");
35
+ if (result.tag === "output") {
36
+ const text = result.render.plain(result.value);
37
+ expect(text).toContain("tier: (none — all tiers visible)");
38
+ expect(text).toContain("channel: normal (stable)");
39
+ expect(text).toContain("config file: (not found)");
40
+ }
41
+ });
42
+
43
+ it("renders show output with configured values", async () => {
44
+ writeFileSync(
45
+ join(dir, "pragma.config.json"),
46
+ '{"tier":"apps/lxd","channel":"experimental"}',
47
+ );
48
+
49
+ const ctx = makeCtx(dir);
50
+ const cmd = buildShowCommand(ctx);
51
+ const result = await cmd.execute({}, ctx);
52
+
53
+ expect(result.tag).toBe("output");
54
+ if (result.tag === "output") {
55
+ const text = result.render.plain(result.value);
56
+ expect(text).toContain("tier: apps/lxd (global → apps → apps/lxd)");
57
+ expect(text).toContain("channel: experimental (stable + experimental)");
58
+ expect(text).toContain("config file:");
59
+ }
60
+ });
61
+ });
@@ -0,0 +1,51 @@
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";
8
+ 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";
12
+
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
+ */
23
+ export default function buildShowCommand(
24
+ ctx: PragmaContext,
25
+ ): 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
+ };
51
+ }
@@ -0,0 +1,84 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import type { Store } from "@canonical/ke";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import { readConfig } from "#config";
7
+ import type { PragmaContext } from "../../shared/context.js";
8
+ import buildTierCommand from "./tier.js";
9
+
10
+ function makeCtx(cwd: string): PragmaContext {
11
+ return {
12
+ cwd,
13
+ globalFlags: { llm: false, format: "text" as const, verbose: false },
14
+ store: {} as Store,
15
+ config: { tier: undefined, channel: "normal" },
16
+ };
17
+ }
18
+
19
+ describe("config tier command", () => {
20
+ let dir: string;
21
+
22
+ beforeEach(() => {
23
+ dir = mkdtempSync(join(tmpdir(), "pragma-cmd-tier-"));
24
+ });
25
+
26
+ afterEach(() => {
27
+ rmSync(dir, { recursive: true, force: true });
28
+ });
29
+
30
+ it("resets tier via --reset flag", async () => {
31
+ writeFileSync(
32
+ join(dir, "pragma.config.json"),
33
+ '{"tier":"apps/lxd","channel":"normal"}',
34
+ );
35
+
36
+ const ctx = makeCtx(dir);
37
+ const cmd = buildTierCommand(ctx);
38
+ const result = await cmd.execute({ reset: true }, ctx);
39
+
40
+ expect(result.tag).toBe("output");
41
+ const config = readConfig(dir);
42
+ expect(config.tier).toBeUndefined();
43
+ expect(config.channel).toBe("normal");
44
+ });
45
+
46
+ it("renders reset output", async () => {
47
+ const ctx = makeCtx(dir);
48
+ const cmd = buildTierCommand(ctx);
49
+ const result = await cmd.execute({ reset: true }, ctx);
50
+
51
+ expect(result.tag).toBe("output");
52
+ if (result.tag === "output") {
53
+ const text = result.render.plain(result.value);
54
+ expect(text).toBe("Reset tier to default.");
55
+ }
56
+ });
57
+
58
+ it("shows current tier when no args", async () => {
59
+ writeFileSync(join(dir, "pragma.config.json"), '{"tier":"apps"}');
60
+
61
+ const ctx = makeCtx(dir);
62
+ const cmd = buildTierCommand(ctx);
63
+ const result = await cmd.execute({}, ctx);
64
+
65
+ expect(result.tag).toBe("output");
66
+ if (result.tag === "output") {
67
+ expect(result.value).toBe("apps");
68
+ const text = result.render.plain(result.value);
69
+ expect(text).toBe("Current tier: apps");
70
+ }
71
+ });
72
+
73
+ it("shows no tier message when none set", async () => {
74
+ const ctx = makeCtx(dir);
75
+ const cmd = buildTierCommand(ctx);
76
+ const result = await cmd.execute({}, ctx);
77
+
78
+ expect(result.tag).toBe("output");
79
+ if (result.tag === "output") {
80
+ const text = result.render.plain(result.value);
81
+ expect(text).toBe("No tier set (all tiers visible).");
82
+ }
83
+ });
84
+ });
@@ -0,0 +1,78 @@
1
+ import {
2
+ type CommandDefinition,
3
+ type CommandResult,
4
+ createOutputResult,
5
+ } from "@canonical/cli-core";
6
+ import { readConfig, writeConfig } from "#config";
7
+ import type { PragmaContext } from "../../shared/context.js";
8
+ import { selectFormatter } from "../../shared/formatters.js";
9
+ import { tierFormatters } from "../formatters/index.js";
10
+ import { validateTier } from "../operations/index.js";
11
+
12
+ /**
13
+ * Build the `pragma config tier` command definition.
14
+ *
15
+ * Supports three modes: set a tier path (validated against the ontology),
16
+ * reset to default, or query the current tier.
17
+ *
18
+ * @param ctx - Pragma context providing cwd, store, and formatter selection.
19
+ * @returns The command definition for `pragma config tier`.
20
+ * @note Impure
21
+ */
22
+ export default function buildTierCommand(
23
+ ctx: PragmaContext,
24
+ ): CommandDefinition {
25
+ return {
26
+ path: ["config", "tier"],
27
+ description: "Set or reset the active tier",
28
+ parameters: [
29
+ {
30
+ name: "path",
31
+ description: "Tier path (e.g., global, apps, apps/lxd)",
32
+ type: "string",
33
+ positional: true,
34
+ },
35
+ {
36
+ name: "reset",
37
+ description: "Reset tier to default (all tiers visible)",
38
+ type: "boolean",
39
+ default: false,
40
+ },
41
+ ],
42
+ meta: {
43
+ examples: ["pragma config tier apps/lxd", "pragma config tier --reset"],
44
+ },
45
+ execute: async (
46
+ params: Record<string, unknown>,
47
+ ): Promise<CommandResult> => {
48
+ const reset = params.reset === true;
49
+ const tierPath = params.path as string | undefined;
50
+
51
+ if (reset) {
52
+ writeConfig(ctx.cwd, { tier: undefined });
53
+ const format = selectFormatter(ctx, tierFormatters.reset);
54
+ return createOutputResult("Reset tier to default.", {
55
+ plain: format,
56
+ });
57
+ }
58
+
59
+ if (!tierPath) {
60
+ const config = readConfig(ctx.cwd);
61
+ const format = selectFormatter(ctx, tierFormatters.query);
62
+ return createOutputResult(config.tier, {
63
+ plain: format,
64
+ });
65
+ }
66
+
67
+ // Validate tier against ontology
68
+ await validateTier(ctx.store, tierPath);
69
+
70
+ writeConfig(ctx.cwd, { tier: tierPath });
71
+ const format = selectFormatter(ctx, tierFormatters.set);
72
+ return createOutputResult(
73
+ { field: "tier", value: tierPath },
74
+ { plain: format },
75
+ );
76
+ },
77
+ };
78
+ }
@@ -0,0 +1,56 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import formatters from "./channel.js";
3
+
4
+ describe("channelFormatters.set", () => {
5
+ const data = { field: "channel", value: "experimental" };
6
+
7
+ it("plain renders set message", () => {
8
+ expect(formatters.set.plain(data)).toBe('Set channel to "experimental".');
9
+ });
10
+
11
+ it("llm renders set message", () => {
12
+ expect(formatters.set.llm(data)).toBe('Set channel to "experimental".');
13
+ });
14
+
15
+ it("json returns valid JSON", () => {
16
+ const parsed = JSON.parse(formatters.set.json(data));
17
+ expect(parsed.field).toBe("channel");
18
+ expect(parsed.value).toBe("experimental");
19
+ });
20
+ });
21
+
22
+ describe("channelFormatters.reset", () => {
23
+ it("plain renders reset message", () => {
24
+ expect(formatters.reset.plain("")).toBe("Reset channel to default.");
25
+ });
26
+
27
+ it("llm renders reset message", () => {
28
+ expect(formatters.reset.llm("")).toBe("Reset channel to default.");
29
+ });
30
+
31
+ it("json returns valid JSON", () => {
32
+ const parsed = JSON.parse(formatters.reset.json(""));
33
+ expect(parsed.field).toBe("channel");
34
+ expect(parsed.reset).toBe(true);
35
+ });
36
+ });
37
+
38
+ describe("channelFormatters.query", () => {
39
+ it("plain shows current channel", () => {
40
+ expect(formatters.query.plain("prerelease")).toBe(
41
+ "Current channel: prerelease",
42
+ );
43
+ });
44
+
45
+ it("llm shows current channel", () => {
46
+ expect(formatters.query.llm("prerelease")).toBe(
47
+ "Current channel: prerelease",
48
+ );
49
+ });
50
+
51
+ it("json returns valid JSON", () => {
52
+ const parsed = JSON.parse(formatters.query.json("prerelease"));
53
+ expect(parsed.field).toBe("channel");
54
+ expect(parsed.value).toBe("prerelease");
55
+ });
56
+ });
@@ -0,0 +1,34 @@
1
+ import type { Formatters } from "../../shared/formatters.js";
2
+
3
+ /**
4
+ * Formatter sets for `pragma config channel` output, grouped by branch:
5
+ *
6
+ * - **set** formats the confirmation after setting a channel (plain/llm/json).
7
+ * - **reset** formats the confirmation after resetting to default (plain/llm/json).
8
+ * - **query** formats the current channel value (plain/llm/json).
9
+ */
10
+ const channelFormatters = {
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 }>,
19
+
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>,
25
+
26
+ query: {
27
+ plain: (channel: string) => `Current channel: ${channel}`,
28
+ llm: (channel: string) => `Current channel: ${channel}`,
29
+ json: (channel: string) =>
30
+ JSON.stringify({ field: "channel", value: channel }),
31
+ } satisfies Formatters<string>,
32
+ };
33
+
34
+ export default channelFormatters;
@@ -0,0 +1,4 @@
1
+ /** @module Formatter sets for config domain output. */
2
+ export { default as channelFormatters } from "./channel.js";
3
+ export { default as showFormatters } from "./show.js";
4
+ export { default as tierFormatters } from "./tier.js";