@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,113 @@
1
+ /**
2
+ * Shared command and entity-display contracts.
3
+ *
4
+ * These types provide the structural common ground for CLI and MCP surfaces.
5
+ */
6
+
7
+ import type { FilterConfig } from "./types.js";
8
+
9
+ export interface ColumnDef<T> {
10
+ readonly key: keyof T & string;
11
+ readonly label: string;
12
+ readonly format?: (value: unknown) => string;
13
+ readonly showWhenEmpty?: boolean;
14
+ }
15
+
16
+ export type SectionKind =
17
+ | "field"
18
+ | "code"
19
+ | "list"
20
+ | "table"
21
+ | "nested-table"
22
+ | "tree";
23
+
24
+ export interface SectionDef<T> {
25
+ readonly key: keyof T & string;
26
+ readonly heading: string;
27
+ readonly kind: SectionKind;
28
+ readonly showWhenEmpty?: boolean;
29
+ }
30
+
31
+ export interface ListParams {
32
+ readonly allTiers?: boolean;
33
+ readonly digest?: boolean;
34
+ readonly detailed?: boolean;
35
+ readonly condensed?: boolean;
36
+ }
37
+
38
+ export interface LookupParams {
39
+ readonly names: readonly string[];
40
+ readonly detailed?: boolean;
41
+ readonly condensed?: boolean;
42
+ }
43
+
44
+ export interface ListResult<T> {
45
+ readonly items: readonly T[];
46
+ readonly filters: FilterConfig;
47
+ readonly disclosure:
48
+ | { readonly level: "summary" }
49
+ | { readonly level: "digest"; readonly maxExampleLength?: number }
50
+ | { readonly level: "detailed" };
51
+ }
52
+
53
+ export interface LookupResult<T> {
54
+ readonly results: readonly T[];
55
+ readonly errors: readonly {
56
+ query: string;
57
+ code: string;
58
+ message: string;
59
+ }[];
60
+ }
61
+
62
+ export interface ShowContract<T> {
63
+ readonly result: T;
64
+ }
65
+
66
+ export interface MutateContract<TParams, TResult> {
67
+ readonly params: TParams;
68
+ readonly result: TResult;
69
+ readonly confirmation: string;
70
+ }
71
+
72
+ export interface ListContract<
73
+ TSummary,
74
+ TDigest extends TSummary,
75
+ TDetailed extends TDigest,
76
+ > {
77
+ readonly params: ListParams;
78
+ readonly result: ListResult<TSummary | TDigest | TDetailed>;
79
+ }
80
+
81
+ export interface LookupContract<TDetailed> {
82
+ readonly params: LookupParams;
83
+ readonly result: LookupResult<TDetailed>;
84
+ }
85
+
86
+ export interface EntityDisplayConfig<
87
+ TSummary,
88
+ TDigest extends TSummary,
89
+ TDetailed extends TDigest,
90
+ > {
91
+ readonly domain: string;
92
+ readonly entityName: string;
93
+ readonly rdfTypes: readonly string[];
94
+ readonly listColumns: readonly ColumnDef<TSummary>[];
95
+ readonly digestColumns: readonly ColumnDef<TDigest>[];
96
+ readonly lookupSections: readonly SectionDef<TDetailed>[];
97
+ readonly emptyRecovery: (filters: FilterConfig) => {
98
+ readonly message: string;
99
+ readonly cli?: string;
100
+ readonly mcp?: {
101
+ readonly tool: string;
102
+ readonly params?: Record<string, unknown>;
103
+ };
104
+ };
105
+ readonly notFoundRecovery: (query: string) => {
106
+ readonly message: string;
107
+ readonly cli?: string;
108
+ readonly mcp?: {
109
+ readonly tool: string;
110
+ readonly params?: Record<string, unknown>;
111
+ };
112
+ };
113
+ }
@@ -0,0 +1,21 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import extractLocalName from "./extractLocalName.js";
3
+ import { PREFIX_MAP } from "./prefixes.js";
4
+
5
+ describe("extractLocalName", () => {
6
+ it("extracts after hash", () => {
7
+ expect(extractLocalName("http://example.org/ns#Thing")).toBe("Thing");
8
+ });
9
+
10
+ it("extracts after last slash", () => {
11
+ expect(extractLocalName(`${PREFIX_MAP.ds}global`)).toBe("global");
12
+ });
13
+
14
+ it("returns full string when no separator", () => {
15
+ expect(extractLocalName("plain")).toBe("plain");
16
+ });
17
+
18
+ it("handles nested path", () => {
19
+ expect(extractLocalName(`${PREFIX_MAP.ds}apps/lxd`)).toBe("lxd");
20
+ });
21
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Extract the local name from a full URI.
3
+ *
4
+ * `"https://ds.canonical.com/global"` → `"global"`
5
+ * `"http://example.org/ns#Thing"` → `"Thing"`
6
+ */
7
+
8
+ export default function extractLocalName(uri: string): string {
9
+ const hashIdx = uri.lastIndexOf("#");
10
+ if (hashIdx !== -1) return uri.slice(hashIdx + 1);
11
+ const slashIdx = uri.lastIndexOf("/");
12
+ if (slashIdx !== -1) return uri.slice(slashIdx + 1);
13
+ return uri;
14
+ }
@@ -0,0 +1,52 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { P } from "../prefixes.js";
3
+ import { buildChannelFilter, CHANNEL_RELEASES } from "./buildChannelFilter.js";
4
+
5
+ describe("CHANNEL_RELEASES", () => {
6
+ it("normal includes only stable", () => {
7
+ expect(CHANNEL_RELEASES.normal).toEqual(["stable"]);
8
+ });
9
+
10
+ it("experimental includes stable + experimental", () => {
11
+ expect(CHANNEL_RELEASES.experimental).toEqual(["stable", "experimental"]);
12
+ });
13
+
14
+ it("prerelease includes all four", () => {
15
+ expect(CHANNEL_RELEASES.prerelease).toEqual([
16
+ "stable",
17
+ "experimental",
18
+ "alpha",
19
+ "beta",
20
+ ]);
21
+ });
22
+ });
23
+
24
+ describe("buildChannelFilter", () => {
25
+ it("generates OPTIONAL + FILTER for normal", () => {
26
+ const result = buildChannelFilter("normal");
27
+ expect(result).toContain(`OPTIONAL { ?component ${P.ds}release ?release }`);
28
+ expect(result).toContain(
29
+ `FILTER(!BOUND(?release) || ?release IN (${P.ds}stable))`,
30
+ );
31
+ });
32
+
33
+ it("generates filter for experimental with two releases", () => {
34
+ const result = buildChannelFilter("experimental");
35
+ expect(result).toContain(
36
+ `?release IN (${P.ds}stable, ${P.ds}experimental)`,
37
+ );
38
+ });
39
+
40
+ it("generates filter for prerelease with all releases", () => {
41
+ const result = buildChannelFilter("prerelease");
42
+ expect(result).toContain(
43
+ `?release IN (${P.ds}stable, ${P.ds}experimental, ${P.ds}alpha, ${P.ds}beta)`,
44
+ );
45
+ });
46
+
47
+ it("uses custom variable name", () => {
48
+ const result = buildChannelFilter("normal", "r");
49
+ expect(result).toContain(`?r IN (${P.ds}stable)`);
50
+ expect(result).toContain("BOUND(?r)");
51
+ });
52
+ });
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Channel filter — release stability visibility.
3
+ *
4
+ * Maps channel settings to the set of visible release levels.
5
+ * Components without a release annotation are treated as stable.
6
+ */
7
+
8
+ import type { Channel } from "#constants";
9
+ import { P } from "../prefixes.js";
10
+
11
+ /**
12
+ * Release levels visible per channel setting.
13
+ */
14
+ export const CHANNEL_RELEASES: Record<Channel, readonly string[]> = {
15
+ normal: ["stable"],
16
+ experimental: ["stable", "experimental"],
17
+ prerelease: ["stable", "experimental", "alpha", "beta"],
18
+ };
19
+
20
+ /**
21
+ * Generate SPARQL clauses for channel visibility.
22
+ *
23
+ * Uses OPTIONAL + FILTER pattern: binds ?release if present,
24
+ * then filters to allowed values OR unbound (= stable default).
25
+ *
26
+ * @param channel - Configured channel.
27
+ * @param varName - SPARQL variable to filter (default: `"release"`).
28
+ * @returns SPARQL OPTIONAL + FILTER clause string.
29
+ */
30
+ export function buildChannelFilter(
31
+ channel: Channel,
32
+ varName = "release",
33
+ ): string {
34
+ const releases = CHANNEL_RELEASES[channel];
35
+ const uriList = releases.map((r) => `${P.ds}${r}`).join(", ");
36
+
37
+ return [
38
+ `OPTIONAL { ?component ${P.ds}release ?${varName} }`,
39
+ `FILTER(!BOUND(?${varName}) || ?${varName} IN (${uriList}))`,
40
+ ].join("\n ");
41
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Build a FilterConfig from runtime config, optionally widening tier.
3
+ */
4
+
5
+ import type { PragmaRuntime } from "../runtime.js";
6
+ import type { FilterConfig } from "../types.js";
7
+
8
+ export default function buildFilterConfig(
9
+ runtime: PragmaRuntime,
10
+ allTiers?: boolean,
11
+ ): FilterConfig {
12
+ return {
13
+ tier: allTiers ? undefined : runtime.config.tier,
14
+ channel: runtime.config.channel,
15
+ };
16
+ }
@@ -0,0 +1,33 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { P } from "../prefixes.js";
3
+ import { buildFilters } from "./buildFilters.js";
4
+
5
+ describe("buildFilters", () => {
6
+ it("returns only channel filter when tier is undefined", () => {
7
+ const result = buildFilters({ tier: undefined, channel: "normal" });
8
+ expect(result).not.toContain("FILTER(?tier");
9
+ expect(result).toContain("FILTER(!BOUND(?release)");
10
+ });
11
+
12
+ it("combines tier and channel filters", () => {
13
+ const result = buildFilters({ tier: "apps/lxd", channel: "experimental" });
14
+ expect(result).toContain(
15
+ `FILTER(?tier IN (${P.ds}global, ${P.ds}apps, ${P.ds}apps_lxd))`,
16
+ );
17
+ expect(result).toContain(`${P.ds}stable, ${P.ds}experimental`);
18
+ });
19
+
20
+ it("returns channel filter for undefined tier + prerelease", () => {
21
+ const result = buildFilters({ tier: undefined, channel: "prerelease" });
22
+ expect(result).toContain(`${P.ds}alpha, ${P.ds}beta`);
23
+ expect(result).not.toContain("FILTER(?tier");
24
+ });
25
+
26
+ it("returns both filters for global tier + normal channel", () => {
27
+ const result = buildFilters({ tier: "global", channel: "normal" });
28
+ expect(result).toContain(`FILTER(?tier IN (${P.ds}global))`);
29
+ expect(result).toContain(
30
+ `FILTER(!BOUND(?release) || ?release IN (${P.ds}stable))`,
31
+ );
32
+ });
33
+ });
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Orthogonal filter combination.
3
+ *
4
+ * Both tier and channel filters apply simultaneously as AND constraints.
5
+ */
6
+
7
+ import type { FilterConfig } from "../types.js";
8
+ import { buildChannelFilter } from "./buildChannelFilter.js";
9
+ import { buildTierFilter } from "./buildTierFilter.js";
10
+
11
+ /**
12
+ * Build combined WHERE clause fragments for tier + channel filters.
13
+ *
14
+ * Returns a string to insert into a SPARQL WHERE clause body.
15
+ * Each filter is independently optional.
16
+ *
17
+ * @param config - Tier and channel filter settings.
18
+ * @returns Combined SPARQL clause fragments.
19
+ */
20
+ export function buildFilters(config: FilterConfig): string {
21
+ const parts: string[] = [];
22
+
23
+ const tierClause = buildTierFilter(config.tier);
24
+ if (tierClause) parts.push(tierClause);
25
+
26
+ const channelClause = buildChannelFilter(config.channel);
27
+ parts.push(channelClause);
28
+
29
+ return parts.join("\n ");
30
+ }
@@ -0,0 +1,78 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { P } from "../prefixes.js";
3
+ import {
4
+ buildTierFilter,
5
+ resolveTierChain,
6
+ tierPathToLocal,
7
+ } from "./buildTierFilter.js";
8
+
9
+ describe("resolveTierChain", () => {
10
+ it("returns empty array for undefined", () => {
11
+ expect(resolveTierChain(undefined)).toEqual([]);
12
+ });
13
+
14
+ it("returns ['global'] for 'global'", () => {
15
+ expect(resolveTierChain("global")).toEqual(["global"]);
16
+ });
17
+
18
+ it("returns ['global', 'apps'] for 'apps'", () => {
19
+ expect(resolveTierChain("apps")).toEqual(["global", "apps"]);
20
+ });
21
+
22
+ it("returns full chain for 'apps/lxd'", () => {
23
+ expect(resolveTierChain("apps/lxd")).toEqual([
24
+ "global",
25
+ "apps",
26
+ "apps/lxd",
27
+ ]);
28
+ });
29
+
30
+ it("handles deep nesting", () => {
31
+ expect(resolveTierChain("apps/lxd/storage")).toEqual([
32
+ "global",
33
+ "apps",
34
+ "apps/lxd",
35
+ "apps/lxd/storage",
36
+ ]);
37
+ });
38
+ });
39
+
40
+ describe("tierPathToLocal", () => {
41
+ it("converts slashes to underscores", () => {
42
+ expect(tierPathToLocal("apps/lxd")).toBe("apps_lxd");
43
+ });
44
+
45
+ it("leaves single segment unchanged", () => {
46
+ expect(tierPathToLocal("global")).toBe("global");
47
+ });
48
+
49
+ it("handles deep paths", () => {
50
+ expect(tierPathToLocal("apps/lxd/storage")).toBe("apps_lxd_storage");
51
+ });
52
+ });
53
+
54
+ describe("buildTierFilter", () => {
55
+ it("returns empty string for undefined tier", () => {
56
+ expect(buildTierFilter(undefined)).toBe("");
57
+ });
58
+
59
+ it("generates FILTER for 'global'", () => {
60
+ expect(buildTierFilter("global")).toBe(`FILTER(?tier IN (${P.ds}global))`);
61
+ });
62
+
63
+ it("generates FILTER for 'apps/lxd' with parent chain", () => {
64
+ expect(buildTierFilter("apps/lxd")).toBe(
65
+ `FILTER(?tier IN (${P.ds}global, ${P.ds}apps, ${P.ds}apps_lxd))`,
66
+ );
67
+ });
68
+
69
+ it("normalizes mixed-case tier paths from config", () => {
70
+ expect(buildTierFilter("Global")).toBe(`FILTER(?tier IN (${P.ds}global))`);
71
+ });
72
+
73
+ it("uses custom variable name", () => {
74
+ expect(buildTierFilter("apps", "t")).toBe(
75
+ `FILTER(?t IN (${P.ds}global, ${P.ds}apps))`,
76
+ );
77
+ });
78
+ });
@@ -0,0 +1,69 @@
1
+ import { P } from "../prefixes.js";
2
+
3
+ /**
4
+ * Tier filter — hierarchical visibility.
5
+ *
6
+ * Setting a tier activates a parent chain filter.
7
+ * `"apps/lxd"` -> visible tiers: `global`, `apps`, `apps/lxd`.
8
+ */
9
+
10
+ /**
11
+ * Resolve the parent chain for a tier path.
12
+ *
13
+ * "apps/lxd" -> ["global", "apps", "apps/lxd"]
14
+ * "apps" -> ["global", "apps"]
15
+ * "global" -> ["global"]
16
+ * undefined -> [] (no filter -- all tiers visible)
17
+ *
18
+ * @param tierPath - Slash-separated tier path, or `undefined` for no filtering.
19
+ * @returns Ordered array of tier paths from root to leaf.
20
+ */
21
+ export function resolveTierChain(tierPath: string | undefined): string[] {
22
+ if (tierPath === undefined) return [];
23
+
24
+ const normalizedTierPath = tierPath.trim().toLowerCase();
25
+
26
+ const chain: string[] = ["global"];
27
+ const segments = normalizedTierPath.split("/");
28
+
29
+ for (let i = 0; i < segments.length; i++) {
30
+ const path = segments.slice(0, i + 1).join("/");
31
+ if (path !== "global") {
32
+ chain.push(path);
33
+ }
34
+ }
35
+
36
+ return chain;
37
+ }
38
+
39
+ /**
40
+ * Convert a tier path to its URI local name.
41
+ * Slashes become underscores: `"apps/lxd"` -> `"apps_lxd"`.
42
+ *
43
+ * @param tierPath - Slash-separated tier path.
44
+ * @returns Underscore-separated local name suitable for URI construction.
45
+ */
46
+ export function tierPathToLocal(tierPath: string): string {
47
+ return tierPath.trim().toLowerCase().replace(/\//g, "_");
48
+ }
49
+
50
+ /**
51
+ * Generate a SPARQL FILTER clause for tier visibility.
52
+ *
53
+ * Returns an empty string when tier is undefined (no filter = all tiers visible).
54
+ *
55
+ * @param tierPath - Configured tier path (e.g., `"apps/lxd"`) or `undefined`.
56
+ * @param varName - SPARQL variable to filter (default: `"tier"`).
57
+ * @returns SPARQL FILTER clause string, or empty string when no tier is set.
58
+ */
59
+ export function buildTierFilter(
60
+ tierPath: string | undefined,
61
+ varName = "tier",
62
+ ): string {
63
+ if (tierPath === undefined) return "";
64
+
65
+ const chain = resolveTierChain(tierPath);
66
+ const uriList = chain.map((t) => `${P.ds}${tierPathToLocal(t)}`).join(", ");
67
+
68
+ return `FILTER(?${varName} IN (${uriList}))`;
69
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Describe active filters as human-readable key-value pairs.
3
+ */
4
+
5
+ import type { FilterConfig } from "../types.js";
6
+
7
+ export default function describeFilters(
8
+ filters: FilterConfig,
9
+ ): Record<string, string> {
10
+ return {
11
+ ...(filters.tier !== undefined && { tier: filters.tier }),
12
+ channel: filters.channel,
13
+ };
14
+ }
@@ -0,0 +1,10 @@
1
+ /** @module Shared SPARQL filter builders for tier and channel visibility. */
2
+ export { buildChannelFilter, CHANNEL_RELEASES } from "./buildChannelFilter.js";
3
+ export { default as buildFilterConfig } from "./buildFilterConfig.js";
4
+ export { buildFilters } from "./buildFilters.js";
5
+ export {
6
+ buildTierFilter,
7
+ resolveTierChain,
8
+ tierPathToLocal,
9
+ } from "./buildTierFilter.js";
10
+ export { default as describeFilters } from "./describeFilters.js";
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared formatter infrastructure for CLI output modes.
3
+ *
4
+ * Every command must support three output modes: plain (terminal),
5
+ * llm (condensed Markdown), and json (structured). The `Formatters<T>`
6
+ * type enforces this contract. `selectFormatter` eliminates the
7
+ * duplicated if/else dispatch in every command's execute function.
8
+ */
9
+
10
+ import type { CommandContext } from "@canonical/cli-core";
11
+
12
+ /**
13
+ * The three output modes every command must support.
14
+ *
15
+ * Each formatter is a pure function from data to string.
16
+ */
17
+ export interface Formatters<T> {
18
+ readonly plain: (data: T) => string;
19
+ readonly llm: (data: T) => string;
20
+ readonly json: (data: T) => string;
21
+ }
22
+
23
+ /**
24
+ * Pick the right formatter based on global flags.
25
+ *
26
+ * Precedence: `--format json` > `--llm` > plain.
27
+ */
28
+ export function selectFormatter<T>(
29
+ ctx: CommandContext,
30
+ formatters: Formatters<T>,
31
+ ): (data: T) => string {
32
+ if (ctx.globalFlags.format === "json") return formatters.json;
33
+ if (ctx.globalFlags.llm) return formatters.llm;
34
+ return formatters.plain;
35
+ }
@@ -0,0 +1,45 @@
1
+ import { PragmaError } from "#error";
2
+ import type { LookupResult } from "./contracts.js";
3
+
4
+ /**
5
+ * Resolve multiple lookup queries and collect structured per-query failures.
6
+ *
7
+ * Used by MCP lookup tools so a single call can return multiple results
8
+ * without failing the entire request when one query is missing.
9
+ */
10
+ export default async function lookupMany<TResult>(
11
+ queries: readonly string[],
12
+ lookup: (query: string) => Promise<TResult>,
13
+ ): Promise<LookupResult<TResult>> {
14
+ const errors: Array<{ query: string; code: string; message: string }> = [];
15
+ const settled = await Promise.allSettled(
16
+ queries.map((query) => lookup(query)),
17
+ );
18
+ const results: TResult[] = [];
19
+
20
+ for (const [index, outcome] of settled.entries()) {
21
+ const query = queries[index];
22
+ if (!query) {
23
+ continue;
24
+ }
25
+
26
+ if (outcome.status === "fulfilled") {
27
+ results.push(outcome.value);
28
+ continue;
29
+ }
30
+
31
+ const error = outcome.reason;
32
+
33
+ if (error instanceof PragmaError) {
34
+ errors.push({
35
+ query,
36
+ code: error.code,
37
+ message: error.message,
38
+ });
39
+ } else {
40
+ throw error;
41
+ }
42
+ }
43
+
44
+ return { results, errors };
45
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Namespace helpers for SPARQL queries.
3
+ *
4
+ * Derived from {@link PREFIX_MAP} via {@link createNamespace} for use
5
+ * in the `sparql` tagged template.
6
+ */
7
+
8
+ import { createNamespace } from "@canonical/ke";
9
+ import { PREFIX_MAP } from "./prefixes.js";
10
+
11
+ /** Design system namespace — classes, properties, and instances (e.g., `ds:Component`). */
12
+ export const ds = createNamespace(PREFIX_MAP.ds);
13
+ /** Component specification namespace — component-level metadata (e.g., `cs:anatomy`). */
14
+ export const cs = createNamespace(PREFIX_MAP.cs);
15
+ /** RDF Schema namespace — core vocabulary (e.g., `rdfs:label`, `rdfs:subClassOf`). */
16
+ export const rdfs = createNamespace(PREFIX_MAP.rdfs);
17
+ /** OWL namespace — ontology constructs (e.g., `owl:Class`, `owl:ObjectProperty`). */
18
+ export const owl = createNamespace(PREFIX_MAP.owl);
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Design system package registry.
3
+ *
4
+ * Single source of truth for all external packages that provide TTL data
5
+ * and/or agent skills. Both `bootStore` (TTL sources) and `resolveSkillSources`
6
+ * (skill discovery) derive their paths from this registry.
7
+ *
8
+ * Each entry declares:
9
+ * - `pkg` — npm package name (resolved via `require.resolve`)
10
+ * - `ttl` — glob patterns for TTL data, relative to the package root
11
+ * - `skills` — subpath to the skills directory, or `undefined` if none
12
+ */
13
+
14
+ import { createRequire } from "node:module";
15
+ import { dirname } from "node:path";
16
+
17
+ const require = createRequire(import.meta.url);
18
+
19
+ export interface PackageDefinition {
20
+ /** npm package name. */
21
+ readonly pkg: string;
22
+ /** Glob patterns for TTL data (relative to package root). */
23
+ readonly ttl: readonly string[];
24
+ /** Subpath to skills directory, or undefined if the package has no skills. */
25
+ readonly skills: string | undefined;
26
+ }
27
+
28
+ export const PACKAGES: readonly PackageDefinition[] = [
29
+ {
30
+ pkg: "@canonical/design-system",
31
+ ttl: ["definitions/ontology.ttl", "data/**/*.ttl"],
32
+ skills: "skills",
33
+ },
34
+ {
35
+ pkg: "@canonical/anatomy-dsl",
36
+ ttl: ["definitions/**/*.ttl"],
37
+ skills: undefined,
38
+ },
39
+ {
40
+ pkg: "@canonical/code-standards",
41
+ ttl: ["definitions/**/*.ttl", "data/**/*.ttl"],
42
+ skills: "skills",
43
+ },
44
+ {
45
+ pkg: "@canonical/pragma-cli",
46
+ ttl: [],
47
+ skills: "skills",
48
+ },
49
+ ];
50
+
51
+ export interface ResolvedPackage {
52
+ /** npm package name. */
53
+ readonly pkg: string;
54
+ /** Absolute path to the package root. */
55
+ readonly dir: string;
56
+ }
57
+
58
+ /**
59
+ * Resolve installed packages from the registry via `require.resolve`.
60
+ * Package-manager agnostic — works with bun, npm, pnpm, yarn.
61
+ * Skips packages that are not installed.
62
+ */
63
+ export function resolvePackages(): ResolvedPackage[] {
64
+ const resolved: ResolvedPackage[] = [];
65
+ for (const { pkg } of PACKAGES) {
66
+ try {
67
+ resolved.push({
68
+ pkg,
69
+ dir: dirname(require.resolve(`${pkg}/package.json`)),
70
+ });
71
+ } catch {
72
+ // package not installed — skip
73
+ }
74
+ }
75
+ return resolved;
76
+ }