@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,133 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { UpgradeData } from "../types.js";
3
+ import {
4
+ renderUpgradeJson,
5
+ renderUpgradeLlm,
6
+ renderUpgradePlain,
7
+ } from "./upgrade.js";
8
+
9
+ function createUpgradeData(overrides: Partial<UpgradeData> = {}): UpgradeData {
10
+ return {
11
+ pm: "bun",
12
+ current: "0.18.0",
13
+ latest: "0.19.0",
14
+ command: "bun update -g @canonical/pragma-cli",
15
+ dryRun: false,
16
+ alreadyLatest: false,
17
+ offline: false,
18
+ executed: true,
19
+ ...overrides,
20
+ };
21
+ }
22
+
23
+ describe("renderUpgradePlain", () => {
24
+ it("shows PM info", () => {
25
+ const output = renderUpgradePlain(createUpgradeData());
26
+ expect(output).toContain("bun (global)");
27
+ });
28
+
29
+ it("shows version transition", () => {
30
+ const output = renderUpgradePlain(createUpgradeData());
31
+ expect(output).toContain("0.18.0");
32
+ expect(output).toContain("0.19.0");
33
+ });
34
+
35
+ it("shows executed message", () => {
36
+ const output = renderUpgradePlain(createUpgradeData());
37
+ expect(output).toContain("done. Updated to 0.19.0");
38
+ });
39
+
40
+ it("shows dry-run message", () => {
41
+ const output = renderUpgradePlain(createUpgradeData({ dryRun: true }));
42
+ expect(output).toContain("Would run");
43
+ expect(output).not.toContain("done.");
44
+ });
45
+
46
+ it("shows already latest", () => {
47
+ const output = renderUpgradePlain(
48
+ createUpgradeData({ alreadyLatest: true }),
49
+ );
50
+ expect(output).toContain("Already at latest version");
51
+ });
52
+
53
+ it("shows offline message", () => {
54
+ const output = renderUpgradePlain(
55
+ createUpgradeData({ offline: true, latest: undefined }),
56
+ );
57
+ expect(output).toContain("Could not reach registry");
58
+ });
59
+
60
+ it("uses npm command for npm PM", () => {
61
+ const output = renderUpgradePlain(
62
+ createUpgradeData({
63
+ pm: "npm",
64
+ command: "npm update -g @canonical/pragma-cli",
65
+ }),
66
+ );
67
+ expect(output).toContain("npm update -g @canonical/pragma-cli");
68
+ });
69
+
70
+ it("uses yarn command for yarn PM", () => {
71
+ const output = renderUpgradePlain(
72
+ createUpgradeData({
73
+ pm: "yarn",
74
+ command: "yarn global upgrade @canonical/pragma-cli",
75
+ }),
76
+ );
77
+ expect(output).toContain("yarn global upgrade @canonical/pragma-cli");
78
+ });
79
+ });
80
+
81
+ describe("renderUpgradeLlm", () => {
82
+ it("shows upgrade transition", () => {
83
+ const output = renderUpgradeLlm(createUpgradeData());
84
+ expect(output).toContain("0.18.0 → 0.19.0");
85
+ });
86
+
87
+ it("shows dry-run info", () => {
88
+ const output = renderUpgradeLlm(createUpgradeData({ dryRun: true }));
89
+ expect(output).toContain("Would upgrade");
90
+ expect(output).toContain("Command:");
91
+ });
92
+
93
+ it("shows already latest", () => {
94
+ const output = renderUpgradeLlm(createUpgradeData({ alreadyLatest: true }));
95
+ expect(output).toContain("Already at latest");
96
+ });
97
+
98
+ it("shows offline", () => {
99
+ const output = renderUpgradeLlm(
100
+ createUpgradeData({ offline: true, latest: undefined }),
101
+ );
102
+ expect(output).toContain("could not reach registry");
103
+ });
104
+ });
105
+
106
+ describe("renderUpgradeJson", () => {
107
+ it("produces valid JSON", () => {
108
+ const data = createUpgradeData();
109
+ const parsed = JSON.parse(renderUpgradeJson(data));
110
+ expect(parsed.pm).toBe("bun");
111
+ expect(parsed.current).toBe("0.18.0");
112
+ expect(parsed.latest).toBe("0.19.0");
113
+ });
114
+
115
+ it("includes all fields", () => {
116
+ const parsed = JSON.parse(renderUpgradeJson(createUpgradeData()));
117
+ expect(parsed).toHaveProperty("dryRun");
118
+ expect(parsed).toHaveProperty("alreadyLatest");
119
+ expect(parsed).toHaveProperty("offline");
120
+ expect(parsed).toHaveProperty("executed");
121
+ expect(parsed).toHaveProperty("command");
122
+ });
123
+
124
+ it("handles offline case", () => {
125
+ const parsed = JSON.parse(
126
+ renderUpgradeJson(
127
+ createUpgradeData({ offline: true, latest: undefined }),
128
+ ),
129
+ );
130
+ expect(parsed.offline).toBe(true);
131
+ expect(parsed.latest).toBeUndefined();
132
+ });
133
+ });
@@ -0,0 +1,68 @@
1
+ import chalk from "chalk";
2
+ import type { UpgradeData } from "../types.js";
3
+
4
+ /**
5
+ * Renders `pragma upgrade` output for a plain terminal.
6
+ *
7
+ * Shows version comparison, dry-run notice, or completion status with chalk styling.
8
+ *
9
+ * @param data - The upgrade outcome data.
10
+ * @returns A formatted terminal string.
11
+ */
12
+ function renderUpgradePlain(data: UpgradeData): string {
13
+ const lines: string[] = [];
14
+
15
+ lines.push(`Installed via: ${data.pm} (global)`);
16
+
17
+ if (data.offline) {
18
+ lines.push("Could not reach registry");
19
+ return lines.join("\n");
20
+ }
21
+
22
+ if (data.alreadyLatest) {
23
+ lines.push(`Already at latest version (${data.current}).`);
24
+ return lines.join("\n");
25
+ }
26
+
27
+ lines.push("");
28
+ lines.push(
29
+ `@canonical/pragma-cli ${data.current} → ${chalk.green(data.latest)}`,
30
+ );
31
+ lines.push("");
32
+
33
+ if (data.dryRun) {
34
+ lines.push(`Would run: ${chalk.cyan(data.command)}`);
35
+ } else {
36
+ lines.push(`Running: ${chalk.cyan(data.command)}`);
37
+ lines.push("");
38
+ lines.push(`done. Updated to ${data.latest}.`);
39
+ }
40
+
41
+ return lines.join("\n");
42
+ }
43
+
44
+ /**
45
+ * Renders `pragma upgrade` output as condensed Markdown for LLM consumption.
46
+ *
47
+ * @param data - The upgrade outcome data.
48
+ * @returns A single-line Markdown string.
49
+ */
50
+ function renderUpgradeLlm(data: UpgradeData): string {
51
+ if (data.offline) return "Upgrade check failed: could not reach registry";
52
+ if (data.alreadyLatest) return `Already at latest version (${data.current})`;
53
+ if (data.dryRun)
54
+ return `Would upgrade: ${data.current} → ${data.latest}\nCommand: ${data.command}`;
55
+ return `Upgraded: ${data.current} → ${data.latest}`;
56
+ }
57
+
58
+ /**
59
+ * Renders `pragma upgrade` output as indented JSON.
60
+ *
61
+ * @param data - The upgrade outcome data.
62
+ * @returns A JSON string.
63
+ */
64
+ function renderUpgradeJson(data: UpgradeData): string {
65
+ return JSON.stringify(data, null, 2);
66
+ }
67
+
68
+ export { renderUpgradeJson, renderUpgradeLlm, renderUpgradePlain };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @module Info domain barrel.
3
+ *
4
+ * Provides the `pragma info` and `pragma upgrade` commands.
5
+ */
6
+
7
+ export { infoCommand, upgradeCommand } from "./commands/index.js";
@@ -0,0 +1,124 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import checkRegistryVersion from "./checkRegistryVersion.js";
3
+
4
+ describe("checkRegistryVersion", () => {
5
+ const originalFetch = globalThis.fetch;
6
+
7
+ beforeEach(() => {
8
+ vi.restoreAllMocks();
9
+ });
10
+
11
+ afterEach(() => {
12
+ globalThis.fetch = originalFetch;
13
+ });
14
+
15
+ it("returns latest version for normal channel", async () => {
16
+ globalThis.fetch = vi.fn().mockResolvedValue({
17
+ ok: true,
18
+ json: () =>
19
+ Promise.resolve({
20
+ "dist-tags": { latest: "0.19.0", experimental: "0.20.0-exp.1" },
21
+ }),
22
+ });
23
+
24
+ const result = await checkRegistryVersion(
25
+ "@canonical/pragma-cli",
26
+ "normal",
27
+ );
28
+
29
+ expect(result).toEqual({ latest: "0.19.0", distTag: "latest" });
30
+ expect(globalThis.fetch).toHaveBeenCalledWith(
31
+ "https://registry.npmjs.org/%40canonical%2Fpragma-cli",
32
+ expect.objectContaining({
33
+ headers: { Accept: "application/json" },
34
+ }),
35
+ );
36
+ });
37
+
38
+ it("returns experimental version for experimental channel", async () => {
39
+ globalThis.fetch = vi.fn().mockResolvedValue({
40
+ ok: true,
41
+ json: () =>
42
+ Promise.resolve({
43
+ "dist-tags": { latest: "0.19.0", experimental: "0.20.0-exp.1" },
44
+ }),
45
+ });
46
+
47
+ const result = await checkRegistryVersion(
48
+ "@canonical/pragma-cli",
49
+ "experimental",
50
+ );
51
+
52
+ expect(result).toEqual({
53
+ latest: "0.20.0-exp.1",
54
+ distTag: "experimental",
55
+ });
56
+ });
57
+
58
+ it("returns next version for prerelease channel", async () => {
59
+ globalThis.fetch = vi.fn().mockResolvedValue({
60
+ ok: true,
61
+ json: () =>
62
+ Promise.resolve({
63
+ "dist-tags": { latest: "0.19.0", next: "0.20.0-rc.1" },
64
+ }),
65
+ });
66
+
67
+ const result = await checkRegistryVersion(
68
+ "@canonical/pragma-cli",
69
+ "prerelease",
70
+ );
71
+
72
+ expect(result).toEqual({ latest: "0.20.0-rc.1", distTag: "next" });
73
+ });
74
+
75
+ it("returns undefined when registry responds with non-ok status", async () => {
76
+ globalThis.fetch = vi.fn().mockResolvedValue({ ok: false, status: 404 });
77
+
78
+ const result = await checkRegistryVersion(
79
+ "@canonical/pragma-cli",
80
+ "normal",
81
+ );
82
+
83
+ expect(result).toBeUndefined();
84
+ });
85
+
86
+ it("returns undefined when dist-tag is missing", async () => {
87
+ globalThis.fetch = vi.fn().mockResolvedValue({
88
+ ok: true,
89
+ json: () => Promise.resolve({ "dist-tags": { latest: "0.19.0" } }),
90
+ });
91
+
92
+ const result = await checkRegistryVersion(
93
+ "@canonical/pragma-cli",
94
+ "prerelease",
95
+ );
96
+
97
+ expect(result).toBeUndefined();
98
+ });
99
+
100
+ it("returns undefined when fetch throws (offline)", async () => {
101
+ globalThis.fetch = vi.fn().mockRejectedValue(new Error("network error"));
102
+
103
+ const result = await checkRegistryVersion(
104
+ "@canonical/pragma-cli",
105
+ "normal",
106
+ );
107
+
108
+ expect(result).toBeUndefined();
109
+ });
110
+
111
+ it("returns undefined when response has no dist-tags", async () => {
112
+ globalThis.fetch = vi.fn().mockResolvedValue({
113
+ ok: true,
114
+ json: () => Promise.resolve({}),
115
+ });
116
+
117
+ const result = await checkRegistryVersion(
118
+ "@canonical/pragma-cli",
119
+ "normal",
120
+ );
121
+
122
+ expect(result).toBeUndefined();
123
+ });
124
+ });
@@ -0,0 +1,45 @@
1
+ import type { Channel } from "#constants";
2
+ import { DIST_TAG_MAP, REGISTRY_TIMEOUT_MS } from "../constants.js";
3
+ import type { RegistryCheckResult } from "../types.js";
4
+
5
+ /**
6
+ * Checks the npm registry for the latest published version of a package.
7
+ *
8
+ * Returns `undefined` when offline or when the registry does not respond
9
+ * within the configured timeout ({@link REGISTRY_TIMEOUT_MS}).
10
+ *
11
+ * @note Impure
12
+ *
13
+ * @param packageName - The npm package name (e.g. `@canonical/pragma-cli`).
14
+ * @param channel - The release channel determining which dist-tag to check.
15
+ * @returns A {@link RegistryCheckResult} with the latest version, or `undefined` on failure.
16
+ */
17
+ async function checkRegistryVersion(
18
+ packageName: string,
19
+ channel: Channel,
20
+ ): Promise<RegistryCheckResult | undefined> {
21
+ const distTag = DIST_TAG_MAP[channel];
22
+ const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}`;
23
+
24
+ try {
25
+ const response = await fetch(url, {
26
+ signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
27
+ headers: { Accept: "application/json" },
28
+ });
29
+
30
+ if (!response.ok) return undefined;
31
+
32
+ const data = (await response.json()) as {
33
+ "dist-tags"?: Record<string, string>;
34
+ };
35
+
36
+ const version = data["dist-tags"]?.[distTag];
37
+ if (!version) return undefined;
38
+
39
+ return { latest: version, distTag };
40
+ } catch {
41
+ return undefined;
42
+ }
43
+ }
44
+
45
+ export default checkRegistryVersion;
@@ -0,0 +1,111 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ const readConfigMock = vi.fn();
4
+ const detectInstallSourceMock = vi.fn();
5
+ const bootStoreMock = vi.fn();
6
+ const checkRegistryVersionMock = vi.fn();
7
+ const collectStoreSummaryMock = vi.fn();
8
+
9
+ vi.mock("#config", async (importOriginal) => ({
10
+ ...(await importOriginal<typeof import("#config")>()),
11
+ readConfig: readConfigMock,
12
+ }));
13
+
14
+ vi.mock("#package-manager", async (importOriginal) => {
15
+ const actual = await importOriginal<typeof import("#package-manager")>();
16
+ return {
17
+ ...actual,
18
+ detectInstallSource: detectInstallSourceMock,
19
+ PM_COMMANDS: {
20
+ ...actual.PM_COMMANDS,
21
+ bun: {
22
+ ...actual.PM_COMMANDS.bun,
23
+ update: (pkg: string) => `bun update ${pkg}`,
24
+ },
25
+ },
26
+ };
27
+ });
28
+
29
+ vi.mock("../../shared/bootStore.js", () => ({
30
+ bootStore: bootStoreMock,
31
+ }));
32
+
33
+ vi.mock("./checkRegistryVersion.js", () => ({
34
+ default: checkRegistryVersionMock,
35
+ }));
36
+
37
+ vi.mock("./collectStoreSummary.js", () => ({
38
+ collectStoreSummary: collectStoreSummaryMock,
39
+ }));
40
+
41
+ describe("collectInfo", () => {
42
+ beforeEach(() => {
43
+ vi.clearAllMocks();
44
+ detectInstallSourceMock.mockReturnValue({
45
+ packageManager: "bun",
46
+ scope: "global",
47
+ label: "bun (global)",
48
+ });
49
+ readConfigMock.mockReturnValue({ tier: "apps/lxd", channel: "normal" });
50
+ });
51
+
52
+ it("includes update information and store summary when available", async () => {
53
+ const dispose = vi.fn();
54
+ bootStoreMock.mockResolvedValue({ dispose });
55
+ checkRegistryVersionMock.mockResolvedValue({
56
+ latest: "9.9.9",
57
+ distTag: "latest",
58
+ });
59
+ collectStoreSummaryMock.mockResolvedValue({
60
+ tripleCount: 42,
61
+ graphNames: ["default"],
62
+ });
63
+
64
+ const { default: collectInfo } = await import("./collectInfo.js");
65
+ const result = await collectInfo("/workspace");
66
+
67
+ expect(result.update).toEqual({
68
+ current: expect.any(String),
69
+ latest: "9.9.9",
70
+ command: "bun update @canonical/pragma-cli",
71
+ });
72
+ expect(result.installSource).toBe("bun (global)");
73
+ expect(result.updateSkipped).toBe(false);
74
+ expect(result.store).toEqual({ tripleCount: 42, graphNames: ["default"] });
75
+ expect(result.tierChain.length).toBeGreaterThan(0);
76
+ expect(dispose).toHaveBeenCalledTimes(1);
77
+ });
78
+
79
+ it("marks update as skipped and omits store when registry and store are unavailable", async () => {
80
+ checkRegistryVersionMock.mockResolvedValue(undefined);
81
+ bootStoreMock.mockRejectedValue(new Error("store unavailable"));
82
+
83
+ const { default: collectInfo } = await import("./collectInfo.js");
84
+ const result = await collectInfo("/workspace");
85
+
86
+ expect(result.update).toBeUndefined();
87
+ expect(result.updateSkipped).toBe(true);
88
+ expect(result.store).toBeUndefined();
89
+ });
90
+
91
+ it("omits the update section when already on the latest version", async () => {
92
+ const { VERSION } = await import("#constants");
93
+ const dispose = vi.fn();
94
+ bootStoreMock.mockResolvedValue({ dispose });
95
+ checkRegistryVersionMock.mockResolvedValue({
96
+ latest: VERSION,
97
+ distTag: "latest",
98
+ });
99
+ collectStoreSummaryMock.mockResolvedValue({
100
+ tripleCount: 10,
101
+ graphNames: ["default"],
102
+ });
103
+
104
+ const { default: collectInfo } = await import("./collectInfo.js");
105
+ const result = await collectInfo("/workspace");
106
+
107
+ expect(result.update).toBeUndefined();
108
+ expect(result.updateSkipped).toBe(false);
109
+ expect(result.store?.tripleCount).toBe(10);
110
+ });
111
+ });
@@ -0,0 +1,68 @@
1
+ import { readConfig } from "#config";
2
+ import { VERSION } from "#constants";
3
+ import { detectInstallSource, PM_COMMANDS } from "#package-manager";
4
+ import { bootStore } from "../../shared/bootStore.js";
5
+ import { CHANNEL_RELEASES } from "../../shared/filters/buildChannelFilter.js";
6
+ import { resolveTierChain } from "../../shared/filters/buildTierFilter.js";
7
+ import type { InfoData } from "../types.js";
8
+ import checkRegistryVersion from "./checkRegistryVersion.js";
9
+ import { collectStoreSummary } from "./collectStoreSummary.js";
10
+
11
+ /**
12
+ * Collects all data for the `pragma info` command.
13
+ *
14
+ * Reads local config, detects the package manager, checks the npm registry
15
+ * for updates, boots a ke store, and gathers store summary statistics.
16
+ *
17
+ * @note Impure
18
+ *
19
+ * @param cwd - The current working directory used to locate `pragma.config.json`.
20
+ * @returns A fully populated {@link InfoData} object.
21
+ */
22
+ export default async function collectInfo(cwd: string): Promise<InfoData> {
23
+ const install = detectInstallSource();
24
+ const pm = install.packageManager;
25
+ const config = readConfig(cwd);
26
+ const tierChain = resolveTierChain(config.tier);
27
+ const channelReleases = CHANNEL_RELEASES[config.channel];
28
+
29
+ const registryResult = await checkRegistryVersion(
30
+ "@canonical/pragma-cli",
31
+ config.channel,
32
+ );
33
+
34
+ let update: InfoData["update"];
35
+ const updateSkipped = registryResult === undefined;
36
+ if (registryResult && registryResult.latest !== VERSION) {
37
+ update = {
38
+ current: VERSION,
39
+ latest: registryResult.latest,
40
+ command: PM_COMMANDS[pm].update("@canonical/pragma-cli"),
41
+ };
42
+ }
43
+
44
+ let store: InfoData["store"];
45
+ let keStore: Awaited<ReturnType<typeof bootStore>> | undefined;
46
+ try {
47
+ keStore = await bootStore({ cwd });
48
+ store = await collectStoreSummary(keStore);
49
+ } catch {
50
+ // Store unavailable — show info without store section
51
+ } finally {
52
+ keStore?.dispose();
53
+ }
54
+
55
+ return {
56
+ version: VERSION,
57
+ pm,
58
+ installSource: install.label,
59
+ configPath: "pragma.config.json",
60
+ tier: config.tier,
61
+ tierChain,
62
+ channel: config.channel,
63
+ channelReleases: [...channelReleases],
64
+ update,
65
+ updateSkipped,
66
+ store,
67
+ };
68
+ }
@@ -0,0 +1,61 @@
1
+ import type { Store } from "@canonical/ke";
2
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
+ import { createTestStore, DS_ONTOLOGY_TTL, DS_TIERS_TTL } from "#testing";
4
+ import { collectStoreSummary } from "./collectStoreSummary.js";
5
+
6
+ describe("collectStoreSummary", () => {
7
+ describe("with default graph only", () => {
8
+ let store: Store;
9
+ let cleanup: () => void;
10
+
11
+ beforeAll(async () => {
12
+ const result = await createTestStore({
13
+ ttl: [DS_ONTOLOGY_TTL, DS_TIERS_TTL].join("\n"),
14
+ });
15
+ store = result.store;
16
+ cleanup = result.cleanup;
17
+ });
18
+
19
+ afterAll(() => {
20
+ cleanup();
21
+ });
22
+
23
+ it("returns a positive triple count", async () => {
24
+ const summary = await collectStoreSummary(store);
25
+ expect(summary.tripleCount).toBeGreaterThan(0);
26
+ });
27
+
28
+ it("returns empty graph names when no named graphs", async () => {
29
+ const summary = await collectStoreSummary(store);
30
+ expect(summary.graphNames).toEqual([]);
31
+ });
32
+ });
33
+
34
+ describe("with named graphs", () => {
35
+ let store: Store;
36
+ let cleanup: () => void;
37
+
38
+ beforeAll(async () => {
39
+ const result = await createTestStore({
40
+ ttl: DS_ONTOLOGY_TTL,
41
+ graphs: [{ graph: "urn:test:tiers", ttl: DS_TIERS_TTL }],
42
+ });
43
+ store = result.store;
44
+ cleanup = result.cleanup;
45
+ });
46
+
47
+ afterAll(() => {
48
+ cleanup();
49
+ });
50
+
51
+ it("returns triple count including named graphs", async () => {
52
+ const summary = await collectStoreSummary(store);
53
+ expect(summary.tripleCount).toBeGreaterThan(0);
54
+ });
55
+
56
+ it("lists named graph URIs", async () => {
57
+ const summary = await collectStoreSummary(store);
58
+ expect(summary.graphNames).toContain("urn:test:tiers");
59
+ });
60
+ });
61
+ });
@@ -0,0 +1,42 @@
1
+ import type { Store } from "@canonical/ke";
2
+ import { buildQuery } from "../../shared/buildQuery.js";
3
+ import type { StoreSummary } from "../types.js";
4
+
5
+ /**
6
+ * Queries the ke store for total triple count and named graph URIs.
7
+ *
8
+ * @note Queries ke store
9
+ *
10
+ * @param store - The ke store to query.
11
+ * @returns A {@link StoreSummary} with `tripleCount` and `graphNames`.
12
+ */
13
+ async function collectStoreSummary(store: Store): Promise<StoreSummary> {
14
+ const countResult = await store.query(
15
+ buildQuery("SELECT (COUNT(*) AS ?count) WHERE { ?s ?p ?o }"),
16
+ );
17
+
18
+ let tripleCount = 0;
19
+ if (countResult.type === "select") {
20
+ const first = countResult.bindings[0];
21
+ if (first) {
22
+ tripleCount = Number.parseInt(first.count ?? "0", 10) || 0;
23
+ }
24
+ }
25
+
26
+ const graphResult = await store.query(
27
+ buildQuery(
28
+ "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } } ORDER BY ?g",
29
+ ),
30
+ );
31
+
32
+ const graphNames: string[] = [];
33
+ if (graphResult.type === "select") {
34
+ for (const binding of graphResult.bindings) {
35
+ if (binding.g) graphNames.push(binding.g);
36
+ }
37
+ }
38
+
39
+ return { tripleCount, graphNames };
40
+ }
41
+
42
+ export { collectStoreSummary };
@@ -0,0 +1,5 @@
1
+ /** @module Barrel for info operations. */
2
+
3
+ export { default as checkRegistryVersion } from "./checkRegistryVersion.js";
4
+ export { default as collectInfo } from "./collectInfo.js";
5
+ export { collectStoreSummary } from "./collectStoreSummary.js";