@canonical/pragma-cli 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (410) hide show
  1. package/README.md +128 -47
  2. package/dist/pragma +0 -0
  3. package/package.json +15 -13
  4. package/src/completions/constants.ts +7 -0
  5. package/src/completions/handleQuery.test.ts +32 -0
  6. package/src/completions/handleQuery.ts +20 -1
  7. package/src/completions/queryCompletions.test.ts +5 -0
  8. package/src/completions/queryCompletions.ts +17 -3
  9. package/src/completions/querySocket.test.ts +31 -0
  10. package/src/completions/querySocket.ts +36 -9
  11. package/src/config/defaultConfig.test.ts +33 -0
  12. package/src/config/defaultConfig.ts +59 -0
  13. package/src/config/defaults.json +17 -0
  14. package/src/config/findProjectConfigPath.test.ts +53 -0
  15. package/src/config/findProjectConfigPath.ts +36 -0
  16. package/src/config/index.ts +17 -2
  17. package/src/config/mergeConfigFileUpdate.ts +58 -0
  18. package/src/config/parseConfigValues.ts +217 -0
  19. package/src/config/readConfig.test.ts +104 -13
  20. package/src/config/readConfig.ts +12 -153
  21. package/src/config/readConfigLayers.test.ts +109 -0
  22. package/src/config/readConfigLayers.ts +118 -0
  23. package/src/config/resolveGlobalConfigPath.ts +13 -0
  24. package/src/config/resolveWriteConfigPath.test.ts +53 -0
  25. package/src/config/resolveWriteConfigPath.ts +31 -0
  26. package/src/config/types.ts +83 -1
  27. package/src/config/writeConfig.ts +25 -55
  28. package/src/constants.ts +3 -1
  29. package/src/domains/block/commands/list.ts +5 -90
  30. package/src/domains/block/commands/lookup.ts +8 -167
  31. package/src/domains/block/commands/sample.ts +2 -1
  32. package/src/domains/block/formatters/list.test.ts +3 -3
  33. package/src/domains/block/formatters/lookup.test.ts +5 -5
  34. package/src/domains/block/mcp/specs.ts +16 -196
  35. package/src/domains/block/orchestration/enrichBlocks.ts +6 -3
  36. package/src/domains/block/orchestration/resolveBlockLookup.ts +2 -1
  37. package/src/domains/block/stories.test.ts +28 -0
  38. package/src/domains/block/stories.ts +260 -0
  39. package/src/domains/config/commands/channel.test.ts +30 -3
  40. package/src/domains/config/commands/channel.ts +25 -8
  41. package/src/domains/config/commands/configScope.ts +46 -0
  42. package/src/domains/config/commands/framework.test.ts +32 -1
  43. package/src/domains/config/commands/framework.ts +26 -8
  44. package/src/domains/config/commands/show.ts +5 -45
  45. package/src/domains/config/commands/tier.test.ts +20 -2
  46. package/src/domains/config/commands/tier.ts +25 -8
  47. package/src/domains/config/commands/trace.test.ts +19 -2
  48. package/src/domains/config/commands/trace.ts +6 -3
  49. package/src/domains/config/formatters/channel.test.ts +20 -6
  50. package/src/domains/config/formatters/channel.ts +14 -11
  51. package/src/domains/config/formatters/framework.ts +14 -11
  52. package/src/domains/config/formatters/show.test.ts +27 -0
  53. package/src/domains/config/formatters/show.ts +27 -4
  54. package/src/domains/config/formatters/tier.test.ts +26 -10
  55. package/src/domains/config/formatters/tier.ts +19 -11
  56. package/src/domains/config/formatters/trace.ts +7 -7
  57. package/src/domains/config/mcp/specs.ts +33 -53
  58. package/src/domains/config/operations/show.test.ts +18 -0
  59. package/src/domains/config/operations/show.ts +7 -1
  60. package/src/domains/config/operations/types.ts +7 -0
  61. package/src/domains/config/operations/validateTier.test.ts +9 -0
  62. package/src/domains/config/operations/validateTier.ts +10 -2
  63. package/src/domains/config/stories.ts +42 -0
  64. package/src/domains/config/tasks/index.ts +1 -0
  65. package/src/domains/config/tasks/setChannel.ts +13 -28
  66. package/src/domains/config/tasks/setFramework.ts +11 -30
  67. package/src/domains/config/tasks/setTier.ts +10 -29
  68. package/src/domains/config/tasks/setTrace.ts +10 -28
  69. package/src/domains/config/tasks/writeConfigField.ts +41 -0
  70. package/src/domains/create/generatorPack/bundled.ts +49 -0
  71. package/src/domains/create/generatorPack/compileGeneratorPack.test.ts +159 -0
  72. package/src/domains/create/generatorPack/compileGeneratorPack.ts +312 -0
  73. package/src/domains/create/index.ts +13 -7
  74. package/src/domains/create/mcp/specs.ts +6 -161
  75. package/src/domains/create/renderGeneratorUi.test.ts +103 -0
  76. package/src/domains/create/renderGeneratorUi.ts +65 -0
  77. package/src/domains/doctor/formatters/doctor.test.ts +50 -2
  78. package/src/domains/doctor/formatters/doctor.ts +90 -38
  79. package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
  80. package/src/domains/doctor/operations/checks/checkMcpCommands.ts +133 -0
  81. package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
  82. package/src/domains/doctor/operations/checks/checkPackageRefs.ts +32 -26
  83. package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +1 -1
  84. package/src/domains/doctor/operations/checks/index.ts +1 -0
  85. package/src/domains/doctor/operations/checks.test.ts +160 -7
  86. package/src/domains/doctor/operations/runChecks.test.ts +15 -6
  87. package/src/domains/doctor/operations/runChecks.ts +2 -0
  88. package/src/domains/doctor/operations/types.ts +23 -1
  89. package/src/domains/graph/commands/inspect.test.ts +2 -2
  90. package/src/domains/graph/commands/query.test.ts +5 -3
  91. package/src/domains/graph/formatters/inspect.ts +7 -7
  92. package/src/domains/graph/formatters/query.test.ts +87 -0
  93. package/src/domains/graph/formatters/query.ts +42 -5
  94. package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
  95. package/src/domains/graph/helpers/resolveUri.ts +28 -21
  96. package/src/domains/graph/operations/inspectUri.test.ts +5 -5
  97. package/src/domains/graphql/commands/build.test.ts +5 -3
  98. package/src/domains/graphql/commands/build.ts +8 -16
  99. package/src/domains/graphql/commands/check.test.ts +5 -3
  100. package/src/domains/graphql/commands/check.ts +7 -13
  101. package/src/domains/graphql/commands/index.ts +1 -0
  102. package/src/domains/graphql/commands/serve.test.ts +46 -0
  103. package/src/domains/graphql/commands/serve.ts +141 -0
  104. package/src/domains/graphql/constants.ts +10 -0
  105. package/src/domains/graphql/helpers/gatherSources.test.ts +92 -0
  106. package/src/domains/graphql/helpers/gatherSources.ts +58 -0
  107. package/src/domains/graphql/helpers/index.ts +2 -0
  108. package/src/domains/graphql/helpers/parsePrefixes.test.ts +3 -3
  109. package/src/domains/graphql/helpers/parsePrefixes.ts +3 -3
  110. package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +9 -0
  111. package/src/domains/graphql/helpers/resolveSourceFiles.ts +24 -3
  112. package/src/domains/graphql/helpers/routeGraphql.test.ts +43 -0
  113. package/src/domains/graphql/helpers/routeGraphql.ts +28 -0
  114. package/src/domains/graphql/index.ts +9 -6
  115. package/src/domains/graphql/operations/compileSchema.test.ts +23 -47
  116. package/src/domains/graphql/operations/compileSchema.ts +23 -25
  117. package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
  118. package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
  119. package/src/domains/graphql/operations/ensureSchemaArtifact.test.ts +167 -0
  120. package/src/domains/graphql/operations/ensureSchemaArtifact.ts +178 -0
  121. package/src/domains/graphql/operations/index.ts +10 -0
  122. package/src/domains/info/formatters/upgrade.test.ts +7 -4
  123. package/src/domains/info/formatters/upgrade.ts +3 -1
  124. package/src/domains/info/operations/collectEntityCounts.test.ts +156 -0
  125. package/src/domains/info/operations/collectEntityCounts.ts +123 -0
  126. package/src/domains/info/operations/collectInfo.test.ts +14 -3
  127. package/src/domains/info/operations/collectInfo.ts +12 -15
  128. package/src/domains/info/operations/index.ts +1 -0
  129. package/src/domains/info/types.ts +13 -0
  130. package/src/domains/llm/capabilities.test.ts +24 -4
  131. package/src/domains/llm/commands/capabilities.ts +12 -3
  132. package/src/domains/llm/commands/llm.ts +5 -1
  133. package/src/domains/llm/data/commandReference.ts +20 -11
  134. package/src/domains/llm/data/decisionTrees.ts +10 -5
  135. package/src/domains/llm/data/toolCatalog.ts +55 -18
  136. package/src/domains/llm/formatters/orientation.ts +5 -1
  137. package/src/domains/llm/llmCommand.test.ts +11 -3
  138. package/src/domains/llm/mcp/specs.ts +3 -4
  139. package/src/domains/llm/operations/collectContext.test.ts +64 -0
  140. package/src/domains/llm/operations/collectContext.ts +7 -17
  141. package/src/domains/modifier/commands/list.ts +5 -38
  142. package/src/domains/modifier/commands/lookup.ts +8 -79
  143. package/src/domains/modifier/commands/sample.ts +2 -1
  144. package/src/domains/modifier/mcp/specs.ts +15 -94
  145. package/src/domains/modifier/operations/lookup.ts +5 -3
  146. package/src/domains/modifier/orchestration/resolveModifierLookup.ts +2 -1
  147. package/src/domains/modifier/stories.test.ts +20 -0
  148. package/src/domains/modifier/stories.ts +86 -0
  149. package/src/domains/ontology/commands/list.test.ts +5 -3
  150. package/src/domains/ontology/commands/list.ts +5 -58
  151. package/src/domains/ontology/commands/show.test.ts +85 -9
  152. package/src/domains/ontology/commands/show.ts +6 -58
  153. package/src/domains/ontology/formatters/index.ts +1 -0
  154. package/src/domains/ontology/formatters/list.ts +37 -12
  155. package/src/domains/ontology/formatters/show.ts +361 -64
  156. package/src/domains/ontology/helpers/buildClassTree.ts +89 -0
  157. package/src/domains/ontology/helpers/completeClassNames.ts +43 -0
  158. package/src/domains/ontology/helpers/expandOntologyIris.ts +79 -0
  159. package/src/domains/ontology/helpers/index.ts +14 -0
  160. package/src/domains/ontology/helpers/queryClasses.ts +32 -16
  161. package/src/domains/ontology/helpers/queryProperties.ts +39 -6
  162. package/src/domains/ontology/helpers/queryTboxFacts.ts +160 -0
  163. package/src/domains/ontology/mcp/specs.ts +7 -84
  164. package/src/domains/ontology/operations/listOntologies.test.ts +80 -3
  165. package/src/domains/ontology/operations/listOntologies.ts +126 -30
  166. package/src/domains/ontology/operations/showOntology.test.ts +131 -12
  167. package/src/domains/ontology/operations/showOntology.ts +289 -7
  168. package/src/domains/ontology/operations/showOntologyRaw.test.ts +4 -2
  169. package/src/domains/ontology/stories.test.ts +36 -0
  170. package/src/domains/ontology/stories.ts +153 -0
  171. package/src/domains/refs/operations/updateRefs.ts +2 -38
  172. package/src/domains/setup/commands/index.ts +1 -0
  173. package/src/domains/setup/commands/setup.ts +70 -0
  174. package/src/domains/setup/commands/skills.test.ts +6 -2
  175. package/src/domains/setup/commands/skills.ts +6 -2
  176. package/src/domains/setup/helpers/runSetupTask.test.ts +148 -150
  177. package/src/domains/setup/helpers/runSetupTask.ts +62 -70
  178. package/src/domains/setup/index.ts +7 -3
  179. package/src/domains/setup/operations/setupLsp.test.ts +3 -2
  180. package/src/domains/setup/operations/setupLsp.ts +7 -2
  181. package/src/domains/setup/operations/setupMcp.test.ts +6 -1
  182. package/src/domains/shared/bootStore.bareCore.test.ts +63 -0
  183. package/src/domains/shared/bootStore.test.ts +82 -0
  184. package/src/domains/shared/bootStore.ts +57 -18
  185. package/src/domains/shared/compactUri.test.ts +11 -0
  186. package/src/domains/shared/compactUri.ts +10 -5
  187. package/src/domains/shared/context.ts +2 -2
  188. package/src/domains/shared/contracts.ts +11 -0
  189. package/src/domains/shared/createInteractivePromptSession.test.ts +439 -0
  190. package/src/domains/shared/createInteractivePromptSession.ts +236 -0
  191. package/src/domains/shared/emptyErrorRecovery.test.ts +23 -26
  192. package/src/domains/shared/extractLocalName.test.ts +3 -3
  193. package/src/domains/shared/formatters.ts +23 -2
  194. package/src/domains/shared/listTiers.ts +40 -0
  195. package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
  196. package/src/domains/shared/loaders/bundledLoader.ts +158 -12
  197. package/src/domains/shared/loaders/gitLoader.ts +1 -2
  198. package/src/domains/shared/loaders/index.ts +4 -1
  199. package/src/domains/shared/loaders/localLoader.ts +2 -4
  200. package/src/domains/shared/loaders/readPackageDir.test.ts +58 -0
  201. package/src/domains/shared/loaders/readPackageDir.ts +82 -9
  202. package/src/domains/shared/loaders/storyAssetsPlugin.test.ts +84 -0
  203. package/src/domains/shared/loaders/storyAssetsPlugin.ts +46 -0
  204. package/src/domains/shared/lookupMany.test.ts +135 -0
  205. package/src/domains/shared/lookupMany.ts +50 -2
  206. package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
  207. package/src/domains/shared/mergeAndParseRefs.ts +44 -0
  208. package/src/domains/shared/namespaces.ts +13 -5
  209. package/src/domains/shared/packages.ts +10 -17
  210. package/src/domains/shared/parseSampleCount.test.ts +47 -0
  211. package/src/domains/shared/parseSampleCount.ts +45 -0
  212. package/src/domains/shared/prefixes.test.ts +211 -0
  213. package/src/domains/shared/prefixes.ts +182 -15
  214. package/src/domains/shared/renderers.ts +5 -5
  215. package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
  216. package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
  217. package/src/domains/shared/resolveLookupExitCode.test.ts +48 -0
  218. package/src/domains/shared/resolveLookupExitCode.ts +42 -0
  219. package/src/domains/shared/runtime.ts +4 -63
  220. package/src/domains/shared/semanticPackage.test.ts +89 -0
  221. package/src/domains/shared/semanticPackage.ts +34 -3
  222. package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
  223. package/src/domains/shared/stories/compileLookupCommand.ts +102 -0
  224. package/src/domains/shared/stories/compileLookupTool.test.ts +105 -0
  225. package/src/domains/shared/stories/compileLookupTool.ts +96 -0
  226. package/src/domains/shared/stories/compileReadCommand.test.ts +121 -0
  227. package/src/domains/shared/stories/compileReadCommand.ts +48 -0
  228. package/src/domains/shared/stories/compileReadTool.test.ts +64 -0
  229. package/src/domains/shared/stories/compileReadTool.ts +38 -0
  230. package/src/domains/shared/stories/condense.test.ts +18 -0
  231. package/src/domains/shared/stories/condense.ts +15 -0
  232. package/src/domains/shared/stories/index.ts +20 -0
  233. package/src/domains/shared/stories/normalizeNames.test.ts +20 -0
  234. package/src/domains/shared/stories/normalizeNames.ts +22 -0
  235. package/src/domains/shared/stories/pack/applyPackFilters.test.ts +151 -0
  236. package/src/domains/shared/stories/pack/applyPackFilters.ts +111 -0
  237. package/src/domains/shared/stories/pack/applyPackSearch.test.ts +57 -0
  238. package/src/domains/shared/stories/pack/applyPackSearch.ts +41 -0
  239. package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +81 -0
  240. package/src/domains/shared/stories/pack/buildLookupQuery.ts +154 -0
  241. package/src/domains/shared/stories/pack/bundled/index.ts +23 -0
  242. package/src/domains/shared/stories/pack/bundled/standardPack.ts +164 -0
  243. package/src/domains/shared/stories/pack/bundled/tierPack.ts +50 -0
  244. package/src/domains/shared/stories/pack/collectPackStories.test.ts +406 -0
  245. package/src/domains/shared/stories/pack/collectPackStories.ts +158 -0
  246. package/src/domains/shared/stories/pack/compilePackCommands.ts +50 -0
  247. package/src/domains/shared/stories/pack/compilePackStories.test.ts +751 -0
  248. package/src/domains/shared/stories/pack/compilePackStories.ts +724 -0
  249. package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +55 -0
  250. package/src/domains/shared/stories/pack/index.ts +42 -0
  251. package/src/domains/shared/stories/pack/reservedVerbs.test.ts +213 -0
  252. package/src/domains/shared/stories/pack/reservedVerbs.ts +170 -0
  253. package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
  254. package/src/domains/shared/stories/pack/standardParity.test.ts +381 -0
  255. package/src/domains/shared/stories/pack/types.ts +224 -0
  256. package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +742 -0
  257. package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +859 -0
  258. package/src/domains/shared/stories/projectCliParameters.test.ts +59 -0
  259. package/src/domains/shared/stories/projectCliParameters.ts +57 -0
  260. package/src/domains/shared/stories/projectToolParams.test.ts +50 -0
  261. package/src/domains/shared/stories/projectToolParams.ts +32 -0
  262. package/src/domains/shared/stories/requirePragmaContext.test.ts +23 -0
  263. package/src/domains/shared/stories/requirePragmaContext.ts +23 -0
  264. package/src/domains/shared/stories/resolveLookupDetailed.test.ts +57 -0
  265. package/src/domains/shared/stories/resolveLookupDetailed.ts +27 -0
  266. package/src/domains/shared/stories/types.ts +179 -0
  267. package/src/domains/shared/suggestions/expandGlob.ts +1 -0
  268. package/src/domains/shared/suggestions/suggestNames.ts +43 -10
  269. package/src/domains/shared/types/index.ts +5 -9
  270. package/src/domains/shared/types/ontology.ts +119 -24
  271. package/src/domains/shared/types/standard.ts +9 -52
  272. package/src/domains/skill/commands/index.ts +3 -1
  273. package/src/domains/skill/commands/list.test.ts +6 -2
  274. package/src/domains/skill/commands/list.ts +5 -63
  275. package/src/domains/skill/commands/lookup.test.ts +118 -0
  276. package/src/domains/skill/commands/lookup.ts +14 -0
  277. package/src/domains/skill/formatters/index.ts +1 -0
  278. package/src/domains/skill/formatters/lookup.test.ts +46 -0
  279. package/src/domains/skill/formatters/lookup.ts +57 -0
  280. package/src/domains/skill/helpers/resolveSkillSources.ts +0 -1
  281. package/src/domains/skill/index.ts +7 -3
  282. package/src/domains/skill/mcp/specs.ts +10 -29
  283. package/src/domains/skill/operations/discover.test.ts +61 -30
  284. package/src/domains/skill/operations/discover.ts +28 -37
  285. package/src/domains/skill/operations/index.ts +2 -1
  286. package/src/domains/skill/operations/list.test.ts +15 -7
  287. package/src/domains/skill/operations/lookup.test.ts +91 -0
  288. package/src/domains/skill/operations/lookup.ts +70 -0
  289. package/src/domains/skill/stories.test.ts +43 -0
  290. package/src/domains/skill/stories.ts +103 -0
  291. package/src/domains/skill/types.ts +8 -0
  292. package/src/domains/token/commands/lookup.test.ts +8 -0
  293. package/src/domains/token/commands/lookup.ts +12 -0
  294. package/src/domains/token/commands/sample.ts +2 -1
  295. package/src/domains/token/featureFlag.ts +17 -0
  296. package/src/domains/token/index.ts +5 -0
  297. package/src/domains/token/mcp/specs.ts +18 -2
  298. package/src/domains/token/orchestration/resolveTokenLookup.ts +2 -1
  299. package/src/domains/trace/commands/resolveTraceLimit.test.ts +31 -0
  300. package/src/domains/trace/commands/show.ts +30 -4
  301. package/src/domains/trace/tracePlugin.test.ts +1 -1
  302. package/src/index.ts +1 -13
  303. package/src/mcp/registerResources.test.ts +382 -74
  304. package/src/mcp/registerResources.ts +5 -348
  305. package/src/mcp/resources/buildGraphIndex.ts +167 -0
  306. package/src/mcp/resources/buildResourceList.test.ts +97 -0
  307. package/src/mcp/resources/buildResourceList.ts +176 -0
  308. package/src/mcp/resources/classifyEntity.test.ts +40 -0
  309. package/src/mcp/resources/classifyEntity.ts +27 -0
  310. package/src/mcp/resources/constants.ts +105 -0
  311. package/src/mcp/resources/displayPredicates.ts +62 -0
  312. package/src/mcp/resources/pickFirstValue.test.ts +29 -0
  313. package/src/mcp/resources/pickFirstValue.ts +26 -0
  314. package/src/mcp/resources/pickPrimaryType.test.ts +41 -0
  315. package/src/mcp/resources/pickPrimaryType.ts +26 -0
  316. package/src/mcp/resources/rankUriCompletions.test.ts +52 -0
  317. package/src/mcp/resources/rankUriCompletions.ts +64 -0
  318. package/src/mcp/resources/readEntity.ts +169 -0
  319. package/src/mcp/resources/registerResources.ts +126 -0
  320. package/src/mcp/resources/types.ts +128 -0
  321. package/src/mcp/tools/index.ts +22 -5
  322. package/src/mcp/tools/registerTools.test.ts +167 -34
  323. package/src/mcp/types.ts +4 -0
  324. package/src/pipeline/collectCommands.test.ts +151 -1
  325. package/src/pipeline/collectCommands.ts +35 -13
  326. package/src/pipeline/createProgram.test.ts +5 -1
  327. package/src/pipeline/createProgram.ts +2 -2
  328. package/src/pipeline/firstRun.test.ts +80 -0
  329. package/src/pipeline/firstRun.ts +99 -0
  330. package/src/pipeline/parseGlobalFlags.test.ts +102 -1
  331. package/src/pipeline/parseGlobalFlags.ts +98 -9
  332. package/src/pipeline/resolveCommandKind.test.ts +12 -0
  333. package/src/pipeline/resolveCommandKind.ts +4 -0
  334. package/src/pipeline/rootHelp.test.ts +87 -0
  335. package/src/pipeline/rootHelp.ts +265 -0
  336. package/src/pipeline/runCli.orchestration.test.ts +28 -12
  337. package/src/pipeline/runCli.test.ts +17 -4
  338. package/src/pipeline/runCli.ts +202 -25
  339. package/src/testing/cli.ts +30 -2
  340. package/src/testing/createTestMcpClient.ts +4 -1
  341. package/src/testing/dsFixtures.ts +21 -4
  342. package/src/testing/index.ts +7 -0
  343. package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
  344. package/src/testing/integration/cli-user-stories.test.ts +63 -0
  345. package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
  346. package/src/testing/integration/edge-cases.test.ts +62 -50
  347. package/src/testing/integration/executor-execution.test.ts +103 -0
  348. package/src/testing/integration/executor-golden.test.ts +145 -0
  349. package/src/testing/integration/mcp-surface.test.ts +40 -15
  350. package/src/testing/integration/parity.test.ts +136 -82
  351. package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
  352. package/src/testing/setupXdgIsolation.ts +26 -0
  353. package/src/testing/standardParityFixtures.ts +35 -0
  354. package/src/testing/store.ts +4 -4
  355. package/src/testing/storyFixtures.ts +63 -0
  356. package/src/domains/create/commands/component.test.ts +0 -166
  357. package/src/domains/create/commands/component.ts +0 -123
  358. package/src/domains/create/commands/index.ts +0 -3
  359. package/src/domains/create/commands/package.test.ts +0 -35
  360. package/src/domains/create/commands/package.ts +0 -21
  361. package/src/domains/create/generators.ts +0 -8
  362. package/src/domains/standard/commands/categories.test.ts +0 -70
  363. package/src/domains/standard/commands/categories.ts +0 -48
  364. package/src/domains/standard/commands/index.ts +0 -6
  365. package/src/domains/standard/commands/list.test.ts +0 -105
  366. package/src/domains/standard/commands/list.ts +0 -90
  367. package/src/domains/standard/commands/lookup.test.ts +0 -135
  368. package/src/domains/standard/commands/lookup.ts +0 -99
  369. package/src/domains/standard/commands/sample.ts +0 -57
  370. package/src/domains/standard/formatters/categories.test.ts +0 -44
  371. package/src/domains/standard/formatters/categories.ts +0 -38
  372. package/src/domains/standard/formatters/index.ts +0 -10
  373. package/src/domains/standard/formatters/list.test.ts +0 -169
  374. package/src/domains/standard/formatters/list.ts +0 -184
  375. package/src/domains/standard/formatters/lookup.test.ts +0 -95
  376. package/src/domains/standard/formatters/lookup.ts +0 -101
  377. package/src/domains/standard/formatters/sample.ts +0 -15
  378. package/src/domains/standard/formatters/types.ts +0 -31
  379. package/src/domains/standard/index.ts +0 -40
  380. package/src/domains/standard/mcp/index.ts +0 -2
  381. package/src/domains/standard/mcp/specs.ts +0 -244
  382. package/src/domains/standard/operations/categories.test.ts +0 -61
  383. package/src/domains/standard/operations/categories.ts +0 -38
  384. package/src/domains/standard/operations/index.ts +0 -6
  385. package/src/domains/standard/operations/list.test.ts +0 -75
  386. package/src/domains/standard/operations/list.ts +0 -64
  387. package/src/domains/standard/operations/lookup.test.ts +0 -58
  388. package/src/domains/standard/operations/lookup.ts +0 -151
  389. package/src/domains/standard/operations/sample.ts +0 -35
  390. package/src/domains/standard/orchestration/buildStandardFilters.ts +0 -11
  391. package/src/domains/standard/orchestration/index.ts +0 -4
  392. package/src/domains/standard/orchestration/resolveStandardList.ts +0 -45
  393. package/src/domains/standard/orchestration/resolveStandardLookup.ts +0 -32
  394. package/src/domains/standard/orchestration/standardEmptyError.test.ts +0 -33
  395. package/src/domains/standard/orchestration/standardEmptyError.ts +0 -29
  396. package/src/domains/standard/standardConfig.ts +0 -42
  397. package/src/domains/standard/types.ts +0 -15
  398. package/src/domains/tier/commands/index.ts +0 -3
  399. package/src/domains/tier/commands/list.test.ts +0 -67
  400. package/src/domains/tier/commands/list.ts +0 -59
  401. package/src/domains/tier/formatters/index.ts +0 -3
  402. package/src/domains/tier/formatters/list.test.ts +0 -33
  403. package/src/domains/tier/formatters/list.ts +0 -45
  404. package/src/domains/tier/index.ts +0 -17
  405. package/src/domains/tier/mcp/index.ts +0 -2
  406. package/src/domains/tier/mcp/specs.ts +0 -38
  407. package/src/domains/tier/operations/index.ts +0 -3
  408. package/src/domains/tier/operations/list.test.ts +0 -32
  409. package/src/domains/tier/operations/list.ts +0 -33
  410. package/src/pipeline/runInteractiveCommand.ts +0 -198
@@ -1,12 +1,44 @@
1
1
  import type { Store } from "@canonical/ke";
2
2
  import { PragmaError } from "#error";
3
- import type { OntologyDetailed } from "../../shared/types/index.js";
3
+ import compactUri from "../../shared/compactUri.js";
4
+ import { PREFIX_MAP } from "../../shared/prefixes.js";
5
+ import type {
6
+ OntologyClass,
7
+ OntologyClassFocus,
8
+ OntologyConstraint,
9
+ OntologyDetailed,
10
+ OntologyMeta,
11
+ OntologyProperty,
12
+ OntologyQueryHint,
13
+ } from "../../shared/types/index.js";
14
+ import buildClassTree, { flattenClassTree } from "../helpers/buildClassTree.js";
4
15
  import queryClasses from "../helpers/queryClasses.js";
16
+ import type { RawOntologyProperty } from "../helpers/queryProperties.js";
5
17
  import queryProperties from "../helpers/queryProperties.js";
18
+ import {
19
+ queryConstraints,
20
+ queryInstanceCounts,
21
+ queryOntologyMeta,
22
+ querySampleInstances,
23
+ } from "../helpers/queryTboxFacts.js";
6
24
  import resolvePrefix from "../helpers/resolvePrefix.js";
7
25
 
26
+ /** Options for {@link showOntology}. */
27
+ export interface ShowOntologyOptions {
28
+ /** Class to deep-dive into (label, local name, or compact IRI). */
29
+ readonly class?: string;
30
+ }
31
+
8
32
  /**
9
- * Returns detailed schema for a namespace, including its classes and properties.
33
+ * Returns the complete TBox structure for a namespace: the class hierarchy
34
+ * (topologically ordered, direct properties attached, instance counts),
35
+ * unattached properties, SHACL constraint summaries, the owl:Ontology
36
+ * header, and — when `options.class` is given — a per-class deep dive.
37
+ *
38
+ * This is the **single** structure every output mode projects; plain,
39
+ * `--llm`, `--format json`, and the MCP envelope must render from it and
40
+ * nothing else. All IRIs are compacted against the store's prefix map,
41
+ * which is included in the result for lossless expansion.
10
42
  *
11
43
  * Accepts a short prefix (e.g. `ds`) or a full namespace URI.
12
44
  *
@@ -14,20 +46,29 @@ import resolvePrefix from "../helpers/resolvePrefix.js";
14
46
  *
15
47
  * @param store - The ke store to query.
16
48
  * @param prefixOrUri - A short prefix or full namespace URI.
49
+ * @param options - Optional class focus.
17
50
  * @returns An {@link OntologyDetailed} with classes and properties.
18
51
  * @throws PragmaError.invalidInput if the prefix or namespace is unknown.
19
- * @throws PragmaError.notFound if the namespace has no classes or properties.
52
+ * @throws PragmaError.notFound if the namespace has no classes or
53
+ * properties, or the focused class does not exist.
20
54
  */
21
55
  export default async function showOntology(
22
56
  store: Store,
23
57
  prefixOrUri: string,
58
+ options: ShowOntologyOptions = {},
24
59
  ): Promise<OntologyDetailed> {
25
60
  const { prefix, namespace } = resolvePrefix(prefixOrUri, store.prefixes);
26
61
 
27
- const classes = await queryClasses(store, namespace);
28
- const properties = await queryProperties(store, namespace);
62
+ const [rawClasses, rawProperties, instanceCounts, rawConstraints, rawMeta] =
63
+ await Promise.all([
64
+ queryClasses(store, namespace),
65
+ queryProperties(store, namespace),
66
+ queryInstanceCounts(store, namespace),
67
+ queryConstraints(store, namespace),
68
+ queryOntologyMeta(store, namespace),
69
+ ]);
29
70
 
30
- if (classes.length === 0 && properties.length === 0) {
71
+ if (rawClasses.length === 0 && rawProperties.length === 0) {
31
72
  throw PragmaError.notFound("ontology", prefixOrUri, {
32
73
  recovery: {
33
74
  message: "List loaded ontologies.",
@@ -37,5 +78,246 @@ export default async function showOntology(
37
78
  });
38
79
  }
39
80
 
40
- return { prefix, namespace, classes, properties };
81
+ // Core RDF vocabularies (xsd etc.) plus the store's resolved package
82
+ // prefixes; the store map wins on collisions.
83
+ const compactionMap: Readonly<Record<string, string>> = {
84
+ ...PREFIX_MAP,
85
+ ...store.prefixes,
86
+ };
87
+ const usedPrefixes = new Set<string>([prefix]);
88
+ const compact = (uri: string): string => {
89
+ const compacted = compactUri(uri, compactionMap);
90
+ const colon = compacted.indexOf(":");
91
+ if (compacted !== uri && colon > 0) {
92
+ usedPrefixes.add(compacted.slice(0, colon));
93
+ }
94
+ return compacted;
95
+ };
96
+
97
+ const toProperty = (raw: RawOntologyProperty): OntologyProperty => ({
98
+ iri: compact(raw.uri),
99
+ label: raw.label,
100
+ kind: raw.kind,
101
+ ...(raw.domain ? { domain: compact(raw.domain) } : {}),
102
+ ...(raw.range ? { range: compact(raw.range) } : {}),
103
+ ...(raw.functional ? { functional: true as const } : {}),
104
+ });
105
+
106
+ // Attach properties to their domain class; the rest are unattached.
107
+ const classUris = new Set(rawClasses.map((c) => c.uri));
108
+ const byDomain = new Map<string, OntologyProperty[]>();
109
+ const unattached: OntologyProperty[] = [];
110
+ for (const raw of rawProperties) {
111
+ if (raw.domain !== undefined && classUris.has(raw.domain)) {
112
+ const attached = byDomain.get(raw.domain) ?? [];
113
+ attached.push(toProperty(raw));
114
+ byDomain.set(raw.domain, attached);
115
+ } else {
116
+ unattached.push(toProperty(raw));
117
+ }
118
+ }
119
+
120
+ const unordered: OntologyClass[] = rawClasses.map((raw) => {
121
+ const instances = instanceCounts.get(raw.uri) ?? 0;
122
+ return {
123
+ iri: compact(raw.uri),
124
+ label: raw.label,
125
+ ...(raw.comment ? { comment: raw.comment } : {}),
126
+ subClassOf: raw.subClassOf.map(compact),
127
+ ...(instances > 0 ? { instances } : {}),
128
+ properties: (byDomain.get(raw.uri) ?? []).sort((a, b) =>
129
+ a.label.localeCompare(b.label),
130
+ ),
131
+ };
132
+ });
133
+
134
+ // Canonical ordering: pre-order walk of the tree every renderer shares.
135
+ const classes = flattenClassTree(buildClassTree(unordered));
136
+
137
+ const constraints: OntologyConstraint[] = rawConstraints.map((raw) => ({
138
+ shape: compact(raw.shape),
139
+ ...(raw.targetClass ? { targetClass: compact(raw.targetClass) } : {}),
140
+ propertyCount: raw.propertyCount,
141
+ }));
142
+
143
+ const meta: OntologyMeta | undefined = rawMeta
144
+ ? {
145
+ ...(rawMeta.title ? { title: rawMeta.title } : {}),
146
+ ...(rawMeta.version ? { version: rawMeta.version } : {}),
147
+ ...(rawMeta.imports.length > 0
148
+ ? { imports: rawMeta.imports.map(compact) }
149
+ : {}),
150
+ }
151
+ : undefined;
152
+
153
+ const focus = options.class
154
+ ? await buildFocus(store, options.class, {
155
+ prefix,
156
+ namespace,
157
+ classes,
158
+ unattached,
159
+ constraints,
160
+ instanceCounts,
161
+ rawClassUris: rawClasses.map((c) => c.uri),
162
+ compactionMap,
163
+ })
164
+ : undefined;
165
+
166
+ const prefixes = Object.fromEntries(
167
+ [...usedPrefixes]
168
+ .sort()
169
+ .map((p) => [p, compactionMap[p]])
170
+ .filter(([, ns]) => ns !== undefined),
171
+ );
172
+
173
+ return {
174
+ prefix,
175
+ namespace,
176
+ prefixes,
177
+ ...(meta ? { meta } : {}),
178
+ classes,
179
+ unattached: unattached.sort((a, b) => a.label.localeCompare(b.label)),
180
+ ...(constraints.length > 0 ? { constraints } : {}),
181
+ ...(focus ? { focus } : {}),
182
+ };
183
+ }
184
+
185
+ interface FocusContext {
186
+ readonly prefix: string;
187
+ readonly namespace: string;
188
+ readonly classes: readonly OntologyClass[];
189
+ readonly unattached: readonly OntologyProperty[];
190
+ readonly constraints: readonly OntologyConstraint[];
191
+ readonly instanceCounts: ReadonlyMap<string, number>;
192
+ readonly rawClassUris: readonly string[];
193
+ readonly compactionMap: Readonly<Record<string, string>>;
194
+ }
195
+
196
+ /**
197
+ * Assemble the per-class deep dive from the already-loaded structure plus
198
+ * one sample-instances query. Everything else (chain, subclasses, reverse
199
+ * references, inherited properties) derives from the namespace data.
200
+ */
201
+ async function buildFocus(
202
+ store: Store,
203
+ classQuery: string,
204
+ ctx: FocusContext,
205
+ ): Promise<OntologyClassFocus> {
206
+ const needle = classQuery.toLowerCase();
207
+ const target = ctx.classes.find(
208
+ (c) =>
209
+ c.iri.toLowerCase() === needle ||
210
+ c.label.toLowerCase() === needle ||
211
+ localName(c.iri).toLowerCase() === needle,
212
+ );
213
+
214
+ if (!target) {
215
+ throw PragmaError.notFound("class", classQuery, {
216
+ suggestions: ctx.classes
217
+ .map((c) => localName(c.iri))
218
+ .filter((name) => name.toLowerCase().includes(needle))
219
+ .slice(0, 5),
220
+ recovery: {
221
+ message: "Show the namespace's class hierarchy.",
222
+ cli: `pragma ontology show ${ctx.prefix}`,
223
+ mcp: { tool: "ontology_show", params: { prefix: ctx.prefix } },
224
+ },
225
+ });
226
+ }
227
+
228
+ const byIri = new Map(ctx.classes.map((c) => [c.iri, c]));
229
+
230
+ // Superclass chain within the namespace, nearest first, cycle-safe.
231
+ const superChain: string[] = [];
232
+ let cursor = target.subClassOf.find((p) => byIri.has(p));
233
+ while (cursor !== undefined && !superChain.includes(cursor)) {
234
+ superChain.push(cursor);
235
+ cursor = byIri.get(cursor)?.subClassOf.find((p) => byIri.has(p));
236
+ }
237
+
238
+ const inheritedProperties = superChain.flatMap(
239
+ (iri) => byIri.get(iri)?.properties ?? [],
240
+ );
241
+
242
+ const allProperties = [
243
+ ...ctx.classes.flatMap((c) => c.properties),
244
+ ...ctx.unattached,
245
+ ];
246
+
247
+ // The focused class's full URI is recoverable from the raw list (same
248
+ // index space as ctx.classes before ordering is irrelevant — match by
249
+ // compacted form).
250
+ const fullUri =
251
+ ctx.rawClassUris.find(
252
+ (uri) => compactUri(uri, ctx.compactionMap) === target.iri,
253
+ ) ?? target.iri;
254
+
255
+ const sampleInstances = (await querySampleInstances(store, fullUri)).map(
256
+ (uri) => compactUri(uri, ctx.compactionMap),
257
+ );
258
+
259
+ const referencedBy = allProperties
260
+ .filter((p) => p.range === target.iri && p.domain !== target.iri)
261
+ .sort((a, b) => a.label.localeCompare(b.label));
262
+
263
+ return {
264
+ iri: target.iri,
265
+ label: target.label,
266
+ ...(target.comment ? { comment: target.comment } : {}),
267
+ superChain,
268
+ subclasses: ctx.classes
269
+ .filter((c) => c.subClassOf.includes(target.iri))
270
+ .map((c) => c.iri)
271
+ .sort(),
272
+ instances: ctx.instanceCounts.get(fullUri) ?? 0,
273
+ directProperties: target.properties,
274
+ inheritedProperties,
275
+ referencedBy,
276
+ sampleInstances,
277
+ queries: buildQueryHints(target, referencedBy, sampleInstances),
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Ready-to-run SPARQL for the natural follow-ups from a class deep dive.
283
+ * Compact IRIs are used throughout — `pragma graph query` resolves them
284
+ * against the store's prefix map, so each hint is directly pasteable.
285
+ */
286
+ function buildQueryHints(
287
+ target: OntologyClass,
288
+ referencedBy: readonly OntologyProperty[],
289
+ sampleInstances: readonly string[],
290
+ ): OntologyQueryHint[] {
291
+ const hints: OntologyQueryHint[] = [
292
+ {
293
+ label: `instances of ${target.iri}`,
294
+ sparql: `SELECT ?instance WHERE { ?instance a ${target.iri} } LIMIT 20`,
295
+ },
296
+ ];
297
+
298
+ const relation =
299
+ target.properties.find((p) => p.kind === "object") ??
300
+ referencedBy.find((p) => p.kind === "object");
301
+ if (relation) {
302
+ hints.push({
303
+ label: `traverse ${relation.iri}`,
304
+ sparql: `SELECT ?from ?to WHERE { ?from ${relation.iri} ?to } LIMIT 10`,
305
+ });
306
+ }
307
+
308
+ const sample = sampleInstances[0];
309
+ if (sample !== undefined) {
310
+ hints.push({
311
+ label: `everything about ${sample}`,
312
+ sparql: `SELECT ?predicate ?object WHERE { ${sample} ?predicate ?object }`,
313
+ });
314
+ }
315
+
316
+ return hints;
317
+ }
318
+
319
+ function localName(iri: string): string {
320
+ const colon = iri.lastIndexOf(":");
321
+ const slash = iri.lastIndexOf("/");
322
+ return iri.slice(Math.max(colon, slash) + 1);
41
323
  }
@@ -2,7 +2,7 @@ import type { Store } from "@canonical/ke";
2
2
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
3
  import { PragmaError } from "#error";
4
4
  import { createTestStore, DS_ALL_TTL } from "#testing";
5
- import { PREFIX_MAP } from "../../shared/prefixes.js";
5
+ import { DEFAULT_PREFIX_MAP } from "../../shared/prefixes.js";
6
6
  import showOntologyRaw from "./showOntologyRaw.js";
7
7
 
8
8
  let store: Store;
@@ -21,7 +21,9 @@ describe("showOntologyRaw", () => {
21
21
  const triples = await showOntologyRaw(store, "ds");
22
22
  expect(triples.length).toBeGreaterThan(0);
23
23
 
24
- const hasDs = triples.some((t) => t.subject.startsWith(PREFIX_MAP.ds));
24
+ const hasDs = triples.some((t) =>
25
+ t.subject.startsWith(DEFAULT_PREFIX_MAP.ds),
26
+ );
25
27
  expect(hasDs).toBe(true);
26
28
  });
27
29
 
@@ -0,0 +1,36 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ontologyListStory, ontologyShowStory } from "./stories.js";
3
+
4
+ describe("ontologyListStory", () => {
5
+ it("renders the ink list view", () => {
6
+ const view = ontologyListStory.renderInk?.([]);
7
+ expect(typeof view).toBe("string");
8
+ expect(view).toContain("Ontologies");
9
+ });
10
+
11
+ it("rejects only empty results", () => {
12
+ expect(ontologyListStory.emptyError?.([], {})).toBeDefined();
13
+ expect(
14
+ ontologyListStory.emptyError?.(
15
+ [
16
+ {
17
+ prefix: "ds",
18
+ namespace: "https://ds.example/",
19
+ classCount: 1,
20
+ propertyCount: 1,
21
+ anatomyCount: 0,
22
+ },
23
+ ],
24
+ {},
25
+ ),
26
+ ).toBeUndefined();
27
+ });
28
+ });
29
+
30
+ describe("ontologyShowStory", () => {
31
+ it("guards against a missing prefix", () => {
32
+ expect(ontologyShowStory.guardParams?.({})).toBeDefined();
33
+ expect(ontologyShowStory.guardParams?.({ prefix: "" })).toBeDefined();
34
+ expect(ontologyShowStory.guardParams?.({ prefix: "ds" })).toBeUndefined();
35
+ });
36
+ });
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Ontology read stories — the single declaration of `ontology list` and
3
+ * `ontology show` for both surfaces.
4
+ *
5
+ * The story kernel compiles these into the CLI commands and MCP tools.
6
+ * Both surfaces now render through the same formatters, so MCP condensed
7
+ * output matches CLI `--llm` output by construction (previously the MCP
8
+ * specs re-implemented the Markdown inline and had drifted).
9
+ */
10
+
11
+ import { PragmaError } from "#error";
12
+ import { createListView } from "#tui";
13
+ import type { ColumnDef } from "../shared/contracts.js";
14
+ import {
15
+ type ReadStory,
16
+ requirePragmaContext,
17
+ } from "../shared/stories/index.js";
18
+ import type {
19
+ OntologyDetailed,
20
+ OntologySummary,
21
+ } from "../shared/types/index.js";
22
+ import type { OntologyShowInput } from "./formatters/index.js";
23
+ import { listFormatters, showFormatters } from "./formatters/index.js";
24
+ import completeClassNames from "./helpers/completeClassNames.js";
25
+ import expandOntologyIris from "./helpers/expandOntologyIris.js";
26
+ import { listOntologies, showOntology } from "./operations/index.js";
27
+
28
+ const ontologyListColumns: readonly ColumnDef<OntologySummary>[] = [
29
+ { key: "prefix", label: "Prefix" },
30
+ { key: "namespace", label: "Namespace" },
31
+ { key: "version", label: "Version" },
32
+ { key: "classCount", label: "Classes" },
33
+ { key: "relationCount", label: "Relations" },
34
+ { key: "attributeCount", label: "Attributes" },
35
+ { key: "shapeCount", label: "Shapes" },
36
+ ];
37
+
38
+ /** The `ontology list` / `ontology_list` read story. */
39
+ export const ontologyListStory: ReadStory<
40
+ OntologySummary[],
41
+ readonly OntologySummary[]
42
+ > = {
43
+ noun: "ontology",
44
+ verb: "list",
45
+ description: "List loaded ontologies",
46
+ toolDescription:
47
+ "List all ontologies loaded in the knowledge graph with class and property counts.",
48
+ params: [],
49
+ examples: ["pragma ontology list", "pragma ontology list --llm"],
50
+ resolve: (rt) => listOntologies(rt.store),
51
+ toOutput: (ontologies) => ontologies,
52
+ formatters: listFormatters,
53
+ toEnvelope: (ontologies) => ({
54
+ data: ontologies,
55
+ meta: { count: ontologies.length },
56
+ }),
57
+ emptyError: (ontologies) =>
58
+ ontologies.length === 0
59
+ ? PragmaError.emptyResults("ontology", {
60
+ recovery: {
61
+ message: "Ensure design system packages are installed.",
62
+ },
63
+ })
64
+ : undefined,
65
+ renderInk: (ontologies) =>
66
+ createListView({
67
+ heading: "Ontologies",
68
+ domain: "ontology",
69
+ items: ontologies,
70
+ columns: ontologyListColumns,
71
+ }),
72
+ };
73
+
74
+ /** The `ontology show <prefix>` / `ontology_show` read story. */
75
+ export const ontologyShowStory: ReadStory<OntologyDetailed, OntologyShowInput> =
76
+ {
77
+ noun: "ontology",
78
+ verb: "show",
79
+ description: "Show ontology schema details",
80
+ toolDescription:
81
+ "Show the TBox for a namespace: class hierarchy with instance counts and relations, plus metadata and constraints.",
82
+ params: [
83
+ {
84
+ name: "prefix",
85
+ type: "string",
86
+ description: "Ontology prefix (e.g. 'ds', 'cs')",
87
+ positional: true,
88
+ required: true,
89
+ complete: async (partial, cmdCtx) => {
90
+ const ctx = requirePragmaContext(cmdCtx);
91
+ const all = await listOntologies(ctx.store);
92
+ return all
93
+ .map((o) => o.prefix)
94
+ .filter(
95
+ (p) =>
96
+ p.length > 0 &&
97
+ p.toLowerCase().startsWith(partial.toLowerCase()),
98
+ );
99
+ },
100
+ },
101
+ {
102
+ name: "class",
103
+ type: "string",
104
+ description:
105
+ "Deep-dive into one class (label, local name, or compact IRI)",
106
+ toolDescription:
107
+ "Class to deep-dive into: super chain, direct + inherited properties, reverse references, sample instances, and follow-up queries",
108
+ complete: async (partial, cmdCtx) => {
109
+ const ctx = requirePragmaContext(cmdCtx);
110
+ return completeClassNames(ctx.store, partial);
111
+ },
112
+ },
113
+ {
114
+ name: "properties",
115
+ type: "boolean",
116
+ description:
117
+ "Include datatype properties (attributes); default shows relations only",
118
+ },
119
+ {
120
+ name: "fullUris",
121
+ type: "boolean",
122
+ description: "Show full URIs instead of compact prefixed IRIs",
123
+ },
124
+ ],
125
+ examples: [
126
+ "pragma ontology show ds",
127
+ "pragma ontology show ds --properties",
128
+ "pragma ontology show ds --full-uris --format json",
129
+ "pragma ontology show ds --class Component",
130
+ ],
131
+ resolve: (rt, params) =>
132
+ showOntology(rt.store, params.prefix as string, {
133
+ class: params.class as string | undefined,
134
+ }),
135
+ // --full-uris is applied here, once, so every projection (plain, llm,
136
+ // json, MCP condensed) inherits the same encoding from the same place.
137
+ toOutput: (ontology, params) => ({
138
+ ontology: params.fullUris ? expandOntologyIris(ontology) : ontology,
139
+ showProperties: Boolean(params.properties),
140
+ }),
141
+ formatters: showFormatters,
142
+ toEnvelope: (ontology) => ({ data: ontology }),
143
+ guardParams: (params) =>
144
+ typeof params.prefix === "string" && params.prefix.length > 0
145
+ ? undefined
146
+ : PragmaError.invalidInput("prefix", "(empty)", {
147
+ recovery: {
148
+ message: "List loaded ontologies to find valid prefixes.",
149
+ cli: "pragma ontology list",
150
+ mcp: { tool: "ontology_list" },
151
+ },
152
+ }),
153
+ };
@@ -8,12 +8,10 @@
8
8
  import { existsSync, readdirSync } from "node:fs";
9
9
  import { join } from "node:path";
10
10
  import { readConfig } from "#config";
11
- import { DEFAULT_PACKAGES } from "../../shared/packages.js";
11
+ import { mergeAndParseRefs } from "../../shared/mergeAndParseRefs.js";
12
12
  import { cloneRef, fetchRef, pruneCache } from "./gitOps.js";
13
13
  import type { PackageRef, RawPackageEntry } from "./parseRef.js";
14
- import { parsePackageEntry } from "./parseRef.js";
15
14
  import { cacheRoot, gitCacheDir } from "./paths.js";
16
- import readGlobalRefs from "./readGlobalRefs.js";
17
15
 
18
16
  // ---------------------------------------------------------------------------
19
17
  // Types
@@ -56,7 +54,7 @@ export default async function updateRefs(
56
54
  options: UpdateRefsOptions,
57
55
  ): Promise<UpdateResult[]> {
58
56
  const config = readConfig(options.cwd);
59
- const refs = mergeEntries(config.packages);
57
+ const refs = mergeAndParseRefs(config.packages);
60
58
  const results: UpdateResult[] = [];
61
59
 
62
60
  for (const ref of refs) {
@@ -137,40 +135,6 @@ export default async function updateRefs(
137
135
  // Helpers
138
136
  // ---------------------------------------------------------------------------
139
137
 
140
- /** Merge global + project entries, parse into PackageRef[]. */
141
- function mergeEntries(
142
- projectPackages?: ReadonlyArray<RawPackageEntry>,
143
- ): PackageRef[] {
144
- const globalEntries = readGlobalRefs();
145
-
146
- if (
147
- (!projectPackages || projectPackages.length === 0) &&
148
- globalEntries.length === 0
149
- ) {
150
- return DEFAULT_PACKAGES.map((pkg) => parsePackageEntry(pkg));
151
- }
152
-
153
- const merged = new Map<string, RawPackageEntry>();
154
-
155
- for (const entry of DEFAULT_PACKAGES) {
156
- const name = typeof entry === "string" ? entry : entry.name;
157
- merged.set(name, entry);
158
- }
159
- for (const entry of globalEntries) {
160
- const name = typeof entry === "string" ? entry : entry.name;
161
- merged.set(name, entry);
162
- }
163
- if (projectPackages) {
164
- merged.clear();
165
- for (const entry of projectPackages) {
166
- const name = typeof entry === "string" ? entry : entry.name;
167
- merged.set(name, entry);
168
- }
169
- }
170
-
171
- return [...merged.values()].map(parsePackageEntry);
172
- }
173
-
174
138
  /**
175
139
  * Remove cache directories that don't match any configured git ref.
176
140
  * Returns list of removed directories.
@@ -3,4 +3,5 @@ export { default as allCommand } from "./all.js";
3
3
  export { default as completionsCommand } from "./completions.js";
4
4
  export { default as lspCommand } from "./lsp.js";
5
5
  export { default as mcpCommand } from "./mcp.js";
6
+ export { default as setupCommand } from "./setup.js";
6
7
  export { default as skillsCommand } from "./skills.js";
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Wires the top-level `pragma setup` command.
3
+ *
4
+ * `setup` is one level more general than `create <thing>`: it configures the
5
+ * whole local environment (completions, LSP, MCP). Unlike `create`, its steps
6
+ * perform *read* effects whose results drive control flow — detecting AI
7
+ * harnesses, checking what is already installed — so it must run for real and
8
+ * report the real outcome. It therefore executes through {@link runSetupTask}
9
+ * (real execution, streamed output) rather than the generator preview-then-
10
+ * execute path, which would render a dry-run preview whose stubbed reads report
11
+ * the wrong state (e.g. "no harnesses detected").
12
+ */
13
+
14
+ import type { CommandDefinition, CommandResult } from "@canonical/cli-core";
15
+ import runSetupTask from "../helpers/runSetupTask.js";
16
+ import setupAll from "../operations/setupAll.js";
17
+
18
+ /**
19
+ * Build the top-level `pragma setup` command definition.
20
+ *
21
+ * @returns The command definition for `pragma setup`.
22
+ * @note Impure
23
+ */
24
+ export default function buildSetupCommand(): CommandDefinition {
25
+ return {
26
+ path: ["setup"],
27
+ description:
28
+ "Configure this project's environment: completions, LSP, and MCP",
29
+ parameters: [
30
+ {
31
+ name: "dryRun",
32
+ description: "Preview changes without writing",
33
+ type: "boolean",
34
+ default: false,
35
+ },
36
+ {
37
+ name: "undo",
38
+ description: "Reverse a previous setup",
39
+ type: "boolean",
40
+ default: false,
41
+ },
42
+ {
43
+ name: "yes",
44
+ description: "Skip all confirmation prompts",
45
+ type: "boolean",
46
+ default: false,
47
+ },
48
+ ],
49
+ meta: {
50
+ examples: [
51
+ "pragma setup",
52
+ "pragma setup --yes",
53
+ "pragma setup --dry-run",
54
+ "pragma setup --undo",
55
+ ],
56
+ },
57
+ execute: async (
58
+ params: Record<string, unknown>,
59
+ ctx,
60
+ ): Promise<CommandResult> =>
61
+ runSetupTask(setupAll(ctx.cwd), {
62
+ dryRun: params.dryRun === true,
63
+ undo: params.undo === true,
64
+ yes: params.yes === true,
65
+ verbose: ctx.globalFlags.verbose,
66
+ llm: ctx.globalFlags.llm,
67
+ format: ctx.globalFlags.format,
68
+ }),
69
+ };
70
+ }