@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,244 +0,0 @@
1
- /**
2
- * MCP tool specs for the standard domain.
3
- *
4
- * Declarative definitions — no MCP imports. The adapter layer
5
- * converts these into registered MCP tools via `registerFromSpec()`.
6
- */
7
-
8
- import type { ToolSpec } from "../../shared/ToolSpec.js";
9
- import {
10
- type StandardListOutput,
11
- categoriesFormatters as standardCatFmt,
12
- listFormatters as standardListFmt,
13
- lookupFormatters as standardLookupFmt,
14
- sampleFormatters as standardSampleFmt,
15
- } from "../formatters/index.js";
16
- import { listCategories, sampleStandards } from "../operations/index.js";
17
- import {
18
- resolveStandardList,
19
- resolveStandardLookup,
20
- } from "../orchestration/index.js";
21
-
22
- const specs: readonly ToolSpec[] = [
23
- {
24
- name: "standard_list",
25
- description:
26
- "List code standards. Optionally filter by category or search term. Use digest/detailed for progressive disclosure.",
27
- params: {
28
- category: {
29
- type: "string",
30
- description: "Filter by category name",
31
- optional: true,
32
- },
33
- search: {
34
- type: "string",
35
- description: "Search in name and description",
36
- optional: true,
37
- },
38
- digest: {
39
- type: "boolean",
40
- description: "Show description and first example for each standard",
41
- optional: true,
42
- },
43
- detailed: {
44
- type: "boolean",
45
- description: "Show full dos/donts for each standard",
46
- optional: true,
47
- },
48
- condensed: {
49
- type: "boolean",
50
- description: "Token-optimized output",
51
- optional: true,
52
- },
53
- },
54
- readOnly: true,
55
- async execute(rt, { category, search, digest, detailed, condensed }) {
56
- const resolution = await resolveStandardList(rt, {
57
- category: category as string | undefined,
58
- search: search as string | undefined,
59
- digest: digest === true,
60
- detailed: detailed === true,
61
- });
62
- const output: StandardListOutput = {
63
- items: resolution.items,
64
- details: resolution.details,
65
- disclosure: resolution.disclosure,
66
- };
67
-
68
- if (condensed) {
69
- const text = standardListFmt.llm(output);
70
- return {
71
- condensed: true,
72
- text,
73
- tokens: `~${Math.ceil(text.length / 4)}`,
74
- };
75
- }
76
-
77
- if (resolution.disclosure.level === "summary") {
78
- return {
79
- data: resolution.items,
80
- meta: { count: resolution.items.length },
81
- };
82
- }
83
-
84
- return {
85
- data: JSON.parse(standardListFmt.json(output)),
86
- meta: {
87
- count: resolution.items.length,
88
- disclosure: resolution.disclosure.level,
89
- },
90
- };
91
- },
92
- },
93
-
94
- {
95
- name: "standard_lookup",
96
- description:
97
- "Get detailed information about one or more code standards including dos and donts with code examples.",
98
- params: {
99
- names: {
100
- type: "string[]",
101
- description: "Standard names or IRIs to look up",
102
- optional: false,
103
- },
104
- detailed: {
105
- type: "boolean",
106
- description:
107
- "Return full details with dos/donts (default: true for MCP)",
108
- optional: true,
109
- },
110
- condensed: {
111
- type: "boolean",
112
- description: "Token-optimized output",
113
- optional: true,
114
- },
115
- },
116
- readOnly: true,
117
- async execute(rt, { names, detailed, condensed }) {
118
- const showDetailed = (detailed as boolean | undefined) ?? true;
119
- const contract = await resolveStandardLookup(rt.store, names as string[]);
120
- const result = contract.result;
121
-
122
- if (condensed) {
123
- const textParts = result.results.map((standard) =>
124
- standardLookupFmt.llm({
125
- standard,
126
- detailed: showDetailed,
127
- }),
128
- );
129
-
130
- if (result.errors.length > 0) {
131
- textParts.push(
132
- [
133
- "### Errors",
134
- ...result.errors.map(
135
- (error) => `- ${error.query}: ${error.message}`,
136
- ),
137
- ].join("\n"),
138
- );
139
- }
140
-
141
- const text = textParts.join("\n\n");
142
- return {
143
- condensed: true,
144
- text,
145
- tokens: `~${Math.ceil(text.length / 4)}`,
146
- };
147
- }
148
-
149
- if (!showDetailed) {
150
- return {
151
- data: {
152
- results: result.results.map(
153
- ({ uri, name, category, description }) => ({
154
- uri,
155
- name,
156
- category,
157
- description,
158
- }),
159
- ),
160
- errors: result.errors,
161
- },
162
- meta: { count: result.results.length },
163
- };
164
- }
165
-
166
- return { data: result, meta: { count: result.results.length } };
167
- },
168
- },
169
-
170
- {
171
- name: "standard_categories",
172
- description: "List all code standard categories.",
173
- params: {
174
- condensed: {
175
- type: "boolean",
176
- description: "Token-optimized output",
177
- optional: true,
178
- },
179
- },
180
- readOnly: true,
181
- async execute(rt, { condensed }) {
182
- const result = await listCategories(rt.store);
183
-
184
- if (condensed) {
185
- const text = standardCatFmt.llm(result);
186
- return {
187
- condensed: true,
188
- text,
189
- tokens: `~${Math.ceil(text.length / 4)}`,
190
- };
191
- }
192
-
193
- return { data: result, meta: { count: result.length } };
194
- },
195
- },
196
-
197
- {
198
- name: "standard_sample",
199
- description:
200
- "Return 1–5 randomly selected complete code standard instances as exemplars. Use BEFORE writing queries to see actual data shapes, property names, and value formats. Each call returns different instances.",
201
- params: {
202
- count: {
203
- type: "string",
204
- description: "Number of samples (1–5, default 2)",
205
- optional: true,
206
- },
207
- condensed: {
208
- type: "boolean",
209
- description: "Token-optimized output",
210
- optional: true,
211
- },
212
- },
213
- readOnly: true,
214
- async execute(rt, { count, condensed }) {
215
- const n = Number(count ?? 2);
216
- const result = await sampleStandards(rt.store, n);
217
- const nextSteps = [
218
- `These are ${result.samples.length} of ${result.totalCount} total standards.`,
219
- "Use standard_lookup to inspect specific standards by name.",
220
- "Use standard_list with category param to filter by category.",
221
- ];
222
-
223
- if (condensed) {
224
- const text = standardSampleFmt.llm({ ...result, nextSteps });
225
- return {
226
- condensed: true,
227
- text,
228
- tokens: `~${Math.ceil(text.length / 4)}`,
229
- };
230
- }
231
-
232
- return {
233
- data: {
234
- samples: result.samples,
235
- totalCount: result.totalCount,
236
- nextSteps,
237
- },
238
- meta: { count: result.samples.length },
239
- };
240
- },
241
- },
242
- ];
243
-
244
- export default specs;
@@ -1,61 +0,0 @@
1
- import type { Store } from "@canonical/ke";
2
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
- import { createTestStore, DS_ALL_TTL } from "#testing";
4
- import { PREFIX_MAP } from "../../shared/prefixes.js";
5
- import listCategories from "./categories.js";
6
-
7
- let store: Store;
8
- let cleanup: () => void;
9
-
10
- beforeAll(async () => {
11
- const result = await createTestStore({ ttl: DS_ALL_TTL });
12
- store = result.store;
13
- cleanup = result.cleanup;
14
- });
15
-
16
- afterAll(() => cleanup());
17
-
18
- describe("listCategories", () => {
19
- it("returns categories with standard counts", async () => {
20
- const result = await listCategories(store);
21
- expect(result.length).toBe(2);
22
-
23
- const react = result.find((c) => c.name === "react");
24
- expect(react?.standardCount).toBe(2);
25
-
26
- const code = result.find((c) => c.name === "code");
27
- expect(code?.standardCount).toBe(1);
28
- });
29
-
30
- it("returns sorted by name", async () => {
31
- const result = await listCategories(store);
32
- const names = result.map((c) => c.name);
33
- const sorted = [...names].sort();
34
- expect(names).toEqual(sorted);
35
- });
36
-
37
- it("includes categories with zero standards", async () => {
38
- const ttlWithEmptyCategory = `
39
- @prefix cs: <${PREFIX_MAP.cs}> .
40
- cs:empty_cat a cs:Category ; cs:slug "empty" .
41
- cs:filled_cat a cs:Category ; cs:slug "filled" .
42
- cs:s1 a cs:CodeStandard ;
43
- cs:name "filled/one" ;
44
- cs:hasCategory cs:filled_cat ;
45
- cs:description "A standard" .
46
- `;
47
- const { store: testStore, cleanup: testCleanup } = await createTestStore({
48
- ttl: ttlWithEmptyCategory,
49
- });
50
- try {
51
- const result = await listCategories(testStore);
52
- const empty = result.find((c) => c.name === "empty");
53
- expect(empty).toBeDefined();
54
- expect(empty?.standardCount).toBe(0);
55
- const filled = result.find((c) => c.name === "filled");
56
- expect(filled?.standardCount).toBe(1);
57
- } finally {
58
- testCleanup();
59
- }
60
- });
61
- });
@@ -1,38 +0,0 @@
1
- /**
2
- * Lists all standard categories with the number of standards in each.
3
- *
4
- * @param store - ke store to query
5
- * @returns array of category summaries ordered by name, empty when none exist
6
- * @note Queries ke store
7
- */
8
-
9
- import type { Store } from "@canonical/ke";
10
- import { buildQuery } from "../../shared/buildQuery.js";
11
- import { P } from "../../shared/prefixes.js";
12
- import type { CategorySummary } from "../../shared/types/index.js";
13
-
14
- export default async function listCategories(
15
- store: Store,
16
- ): Promise<CategorySummary[]> {
17
- const result = await store.query(
18
- buildQuery(`
19
- SELECT ?categoryName (COUNT(?standard) AS ?count)
20
- WHERE {
21
- ?cat a ${P.cs}Category ;
22
- ${P.cs}slug ?categoryName .
23
- OPTIONAL {
24
- ?standard a ${P.cs}CodeStandard ;
25
- ${P.cs}hasCategory ?cat .
26
- }
27
- }
28
- GROUP BY ?categoryName
29
- ORDER BY ?categoryName
30
- `),
31
- );
32
-
33
- if (result.type !== "select") return [];
34
- return result.bindings.map((b) => ({
35
- name: b.categoryName ?? "",
36
- standardCount: Number.parseInt(b.count ?? "0", 10) || 0,
37
- }));
38
- }
@@ -1,6 +0,0 @@
1
- /** @module Re-exports standard operations (`listCategories`, `listStandards`, `lookupStandard`, `sampleStandards`). */
2
-
3
- export { default as listCategories } from "./categories.js";
4
- export { default as listStandards } from "./list.js";
5
- export { default as lookupStandard } from "./lookup.js";
6
- export { default as sampleStandards } from "./sample.js";
@@ -1,75 +0,0 @@
1
- import type { Store } from "@canonical/ke";
2
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
- import { createTestStore, DS_ALL_TTL } from "#testing";
4
- import listStandards from "./list.js";
5
-
6
- let store: Store;
7
- let cleanup: () => void;
8
-
9
- beforeAll(async () => {
10
- const result = await createTestStore({ ttl: DS_ALL_TTL });
11
- store = result.store;
12
- cleanup = result.cleanup;
13
- });
14
-
15
- afterAll(() => cleanup());
16
-
17
- describe("listStandards", () => {
18
- it("returns all standards", async () => {
19
- const result = await listStandards(store);
20
- expect(result.length).toBe(3);
21
- const names = result.map((s) => s.name);
22
- expect(names).toContain("react/component/folder-structure");
23
- expect(names).toContain("react/component/props");
24
- expect(names).toContain("code/function/purity");
25
- });
26
-
27
- it("includes category names", async () => {
28
- const result = await listStandards(store);
29
- const folder = result.find(
30
- (s) => s.name === "react/component/folder-structure",
31
- );
32
- expect(folder?.category).toBe("react");
33
- });
34
-
35
- it("returns sorted by name", async () => {
36
- const result = await listStandards(store);
37
- const names = result.map((s) => s.name);
38
- const sorted = [...names].sort();
39
- expect(names).toEqual(sorted);
40
- });
41
-
42
- it("filters by category", async () => {
43
- const result = await listStandards(store, { category: "react" });
44
- expect(result.length).toBe(2);
45
- for (const s of result) {
46
- expect(s.category).toBe("react");
47
- }
48
- });
49
-
50
- it("filters by search term in name", async () => {
51
- const result = await listStandards(store, { search: "folder" });
52
- expect(result.length).toBe(1);
53
- expect(result[0]?.name).toBe("react/component/folder-structure");
54
- });
55
-
56
- it("filters by search term in description", async () => {
57
- const result = await listStandards(store, { search: "pure" });
58
- expect(result.length).toBe(1);
59
- expect(result[0]?.name).toBe("code/function/purity");
60
- });
61
-
62
- it("returns empty for non-matching category", async () => {
63
- const result = await listStandards(store, { category: "nonexistent" });
64
- expect(result.length).toBe(0);
65
- });
66
-
67
- it("combines category and search filters", async () => {
68
- const result = await listStandards(store, {
69
- category: "react",
70
- search: "props",
71
- });
72
- expect(result.length).toBe(1);
73
- expect(result[0]?.name).toBe("react/component/props");
74
- });
75
- });
@@ -1,64 +0,0 @@
1
- /**
2
- * Lists all code standards, optionally filtered by category or search term.
3
- *
4
- * @param store - ke store to query
5
- * @param filters - optional category and/or search text filters
6
- * @returns array of standard summaries ordered by name, empty when none match
7
- * @note Queries ke store
8
- */
9
-
10
- import type { Store, URI } from "@canonical/ke";
11
- import { escapeSparqlValue } from "@canonical/ke";
12
- import { buildQuery } from "../../shared/buildQuery.js";
13
- import { P } from "../../shared/prefixes.js";
14
- import type {
15
- StandardListFilters,
16
- StandardSummary,
17
- } from "../../shared/types/index.js";
18
-
19
- export default async function listStandards(
20
- store: Store,
21
- filters?: StandardListFilters,
22
- ): Promise<StandardSummary[]> {
23
- const filterClauses: string[] = [];
24
-
25
- if (filters?.category) {
26
- const escaped = escapeSparqlValue(filters.category.toLowerCase());
27
- filterClauses.push(
28
- `?standard ${P.cs}hasCategory ?filterCat . ?filterCat ${P.cs}slug ?catSlug . FILTER(?catSlug = ${escaped})`,
29
- );
30
- }
31
-
32
- if (filters?.search) {
33
- const escaped = escapeSparqlValue(filters.search.toLowerCase());
34
- filterClauses.push(
35
- `FILTER(CONTAINS(LCASE(?name), ${escaped}) || CONTAINS(LCASE(?description), ${escaped}))`,
36
- );
37
- }
38
-
39
- const result = await store.query(
40
- buildQuery(`
41
- SELECT ?standard ?name ?categoryName ?description
42
- WHERE {
43
- ?standard a ${P.cs}CodeStandard ;
44
- ${P.cs}name ?name ;
45
- ${P.cs}description ?description .
46
- OPTIONAL {
47
- ?standard ${P.cs}hasCategory ?cat .
48
- ?cat ${P.cs}slug ?categoryName .
49
- }
50
- ${filterClauses.join("\n ")}
51
- }
52
- ORDER BY ?name
53
- `),
54
- );
55
-
56
- if (result.type !== "select") return [];
57
-
58
- return result.bindings.map((b) => ({
59
- uri: (b.standard ?? "") as URI,
60
- name: b.name ?? "",
61
- category: b.categoryName ?? "",
62
- description: b.description ?? "",
63
- }));
64
- }
@@ -1,58 +0,0 @@
1
- import type { Store } from "@canonical/ke";
2
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
3
- import { PragmaError } from "#error";
4
- import { createTestStore, DS_ALL_TTL } from "#testing";
5
- import lookupStandard from "./lookup.js";
6
-
7
- let store: Store;
8
- let cleanup: () => void;
9
-
10
- beforeAll(async () => {
11
- const result = await createTestStore({ ttl: DS_ALL_TTL });
12
- store = result.store;
13
- cleanup = result.cleanup;
14
- });
15
-
16
- afterAll(() => cleanup());
17
-
18
- describe("lookupStandard", () => {
19
- it("returns detailed data with dos and donts", async () => {
20
- const result = await lookupStandard(
21
- store,
22
- "react/component/folder-structure",
23
- );
24
- expect(result.name).toBe("react/component/folder-structure");
25
- expect(result.category).toBe("react");
26
- expect(result.dos.length).toBeGreaterThan(0);
27
- expect(result.donts.length).toBeGreaterThan(0);
28
- });
29
-
30
- it("throws PragmaError.notFound for unknown standard", async () => {
31
- await expect(lookupStandard(store, "nonexistent")).rejects.toThrow(
32
- PragmaError,
33
- );
34
-
35
- try {
36
- await lookupStandard(store, "nonexistent");
37
- } catch (e) {
38
- expect((e as PragmaError).code).toBe("ENTITY_NOT_FOUND");
39
- }
40
- });
41
-
42
- it("resolves prefixed IRIs and compacts extends", async () => {
43
- const result = await lookupStandard(store, "cs:react_props");
44
- expect(result.name).toBe("react/component/props");
45
- expect(result.extends).toBe("cs:react_folder");
46
- });
47
-
48
- it("resolves full IRIs", async () => {
49
- const result = await lookupStandard(
50
- store,
51
- "http://pragma.canonical.com/codestandards#react_props",
52
- );
53
- expect(result.name).toBe("react/component/props");
54
- expect(result.uri).toBe(
55
- "http://pragma.canonical.com/codestandards#react_props",
56
- );
57
- });
58
- });
@@ -1,151 +0,0 @@
1
- /**
2
- * Look up detailed information for a single code standard by name.
3
- *
4
- * Queries the base standard data plus its dos and donts code blocks,
5
- * then assembles a {@link StandardDetailed} object.
6
- *
7
- * @param store - ke store to query
8
- * @param name - standard name (e.g. "react/component/folder-structure")
9
- * @returns full standard detail including dos/donts code blocks
10
- * @throws PragmaError.notFound if the standard does not exist
11
- * @note Queries ke store
12
- */
13
-
14
- import type { Store, URI } from "@canonical/ke";
15
- import { escapeSparqlValue } from "@canonical/ke";
16
- import { PragmaError } from "#error";
17
- import resolveUri from "../../graph/helpers/resolveUri.js";
18
- import { buildQuery } from "../../shared/buildQuery.js";
19
- import compactUri from "../../shared/compactUri.js";
20
- import { P } from "../../shared/prefixes.js";
21
- import {
22
- detectCrossDomain,
23
- listDomainNames,
24
- suggestNames,
25
- } from "../../shared/suggestions/index.js";
26
- import type { CodeBlock, StandardDetailed } from "../../shared/types/index.js";
27
-
28
- export default async function lookupStandard(
29
- store: Store,
30
- nameOrUri: string,
31
- ): Promise<StandardDetailed> {
32
- const subjectClause = buildLookupSubjectClause(nameOrUri, store.prefixes);
33
- const bindClause =
34
- subjectClause === null ? "" : `BIND(${subjectClause} AS ?standard)`;
35
- const matchClause =
36
- subjectClause === null
37
- ? `?standard ${P.cs}name ${escapeSparqlValue(nameOrUri)} .`
38
- : "";
39
-
40
- const baseResult = await store.query(
41
- buildQuery(`
42
- SELECT ?standard ?name ?categoryName ?description ?extends
43
- WHERE {
44
- ${bindClause}
45
- ?standard a ${P.cs}CodeStandard ;
46
- ${P.cs}name ?name ;
47
- ${P.cs}description ?description .
48
- ${matchClause}
49
- OPTIONAL {
50
- ?standard ${P.cs}hasCategory ?cat .
51
- ?cat ${P.cs}slug ?categoryName .
52
- }
53
- OPTIONAL { ?standard ${P.cs}extends ?extends }
54
- }
55
- LIMIT 1
56
- `),
57
- );
58
-
59
- if (baseResult.type !== "select" || baseResult.bindings.length === 0) {
60
- const candidates = await listDomainNames(store, "standard");
61
- const crossDomain = await detectCrossDomain(nameOrUri, "standard", store);
62
- throw PragmaError.notFound("standard", nameOrUri, {
63
- suggestions: suggestNames(nameOrUri, candidates),
64
- recovery: {
65
- message: "List available standards.",
66
- cli: "pragma standard list",
67
- mcp: { tool: "standard_list" },
68
- },
69
- crossDomain: crossDomain ?? undefined,
70
- });
71
- }
72
-
73
- // Safe: length check above guarantees bindings[0] exists
74
- const base = baseResult.bindings[0] as (typeof baseResult.bindings)[number];
75
- const standardUri = base.standard;
76
-
77
- // Fetch dos (cs:do → cs:Example with cs:description, cs:language, cs:code)
78
- const dosResult = await store.query(
79
- buildQuery(`
80
- SELECT ?description ?language ?code
81
- WHERE {
82
- <${standardUri}> ${P.cs}do ?example .
83
- OPTIONAL { ?example ${P.cs}description ?description }
84
- OPTIONAL { ?example ${P.cs}language ?language }
85
- OPTIONAL { ?example ${P.cs}code ?code }
86
- }
87
- `),
88
- );
89
-
90
- const dos: CodeBlock[] =
91
- dosResult.type === "select"
92
- ? dosResult.bindings.map((b) => ({
93
- language: b.language ?? "typescript",
94
- code: b.code ?? "",
95
- caption: b.description,
96
- }))
97
- : [];
98
-
99
- // Fetch donts (cs:dont → cs:Example with cs:description, cs:language, cs:code)
100
- const dontsResult = await store.query(
101
- buildQuery(`
102
- SELECT ?description ?language ?code
103
- WHERE {
104
- <${standardUri}> ${P.cs}dont ?example .
105
- OPTIONAL { ?example ${P.cs}description ?description }
106
- OPTIONAL { ?example ${P.cs}language ?language }
107
- OPTIONAL { ?example ${P.cs}code ?code }
108
- }
109
- `),
110
- );
111
-
112
- const donts: CodeBlock[] =
113
- dontsResult.type === "select"
114
- ? dontsResult.bindings.map((b) => ({
115
- language: b.language ?? "typescript",
116
- code: b.code ?? "",
117
- caption: b.description,
118
- }))
119
- : [];
120
-
121
- return {
122
- uri: (standardUri ?? "") as URI,
123
- name: base.name ?? nameOrUri,
124
- category: base.categoryName ?? "",
125
- description: base.description ?? "",
126
- extends: base.extends
127
- ? compactUri(base.extends, store.prefixes)
128
- : undefined,
129
- dos,
130
- donts,
131
- };
132
- }
133
-
134
- function buildLookupSubjectClause(
135
- query: string,
136
- prefixes: Readonly<Record<string, string>>,
137
- ): string | null {
138
- if (!looksLikeUri(query)) {
139
- return null;
140
- }
141
-
142
- return `<${resolveUri(query, prefixes)}>`;
143
- }
144
-
145
- function looksLikeUri(query: string): boolean {
146
- return (
147
- query.startsWith("http://") ||
148
- query.startsWith("https://") ||
149
- query.includes(":")
150
- );
151
- }