@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,5 +1,7 @@
1
1
  /** Tool catalog with behavioral hints for agent orientation. */
2
2
 
3
+ import { TOKEN_READ_SURFACE_ENABLED } from "../../token/featureFlag.js";
4
+
3
5
  export interface ToolEntry {
4
6
  readonly name: string;
5
7
  readonly category: "read" | "write" | "orientation" | "diagnostic";
@@ -49,18 +51,22 @@ export const TOOL_CATALOG: readonly ToolEntry[] = [
49
51
  use_when:
50
52
  "Need values and usage details for specific modifier families by name",
51
53
  },
52
- {
53
- name: "token_list",
54
- category: "read",
55
- use_when:
56
- "Browsing design tokens, optionally filtered by category (color, spacing, etc.)",
57
- },
58
- {
59
- name: "token_lookup",
60
- category: "read",
61
- use_when:
62
- "Need theme values and resolution details for specific tokens by name or IRI",
63
- },
54
+ ...(TOKEN_READ_SURFACE_ENABLED
55
+ ? ([
56
+ {
57
+ name: "token_list",
58
+ category: "read",
59
+ use_when:
60
+ "Browsing design tokens, optionally filtered by category (color, spacing, etc.)",
61
+ },
62
+ {
63
+ name: "token_lookup",
64
+ category: "read",
65
+ use_when:
66
+ "Need theme values and resolution details for specific tokens by name or IRI",
67
+ },
68
+ ] as const)
69
+ : []),
64
70
  {
65
71
  name: "tier_list",
66
72
  category: "read",
@@ -101,23 +107,33 @@ export const TOOL_CATALOG: readonly ToolEntry[] = [
101
107
  use_when: "Discovering agent skills provided by installed packages",
102
108
  },
103
109
  {
104
- name: "block_sample",
110
+ name: "skill_lookup",
105
111
  category: "read",
106
112
  use_when:
107
- "See actual block data shapes before querying — returns random instances each call, prevents guessing at property names",
113
+ "Loading full SKILL.md instructions for a specific agent skill by name",
108
114
  },
109
115
  {
110
- name: "standard_sample",
116
+ name: "block_sample",
111
117
  category: "read",
112
118
  use_when:
113
- "See actual standard data shapes (with dos/donts) before querying — returns random instances each call",
119
+ "See actual block data shapes before querying — returns random instances each call, prevents guessing at property names",
114
120
  },
115
121
  {
116
- name: "token_sample",
122
+ name: "standard_sample",
117
123
  category: "read",
118
124
  use_when:
119
- "See actual token data shapes (with theme values) before querying — returns random instances each call",
125
+ "See actual standard data shapes (with dos/donts) before querying — returns random instances each call",
120
126
  },
127
+ ...(TOKEN_READ_SURFACE_ENABLED
128
+ ? ([
129
+ {
130
+ name: "token_sample",
131
+ category: "read",
132
+ use_when:
133
+ "See actual token data shapes (with theme values) before querying — returns random instances each call",
134
+ },
135
+ ] as const)
136
+ : []),
121
137
  {
122
138
  name: "modifier_sample",
123
139
  category: "read",
@@ -154,6 +170,27 @@ export const TOOL_CATALOG: readonly ToolEntry[] = [
154
170
  use_when:
155
171
  "Scaffolding a new npm package with proper monorepo configuration",
156
172
  },
173
+ {
174
+ name: "create_application",
175
+ category: "write",
176
+ use_when:
177
+ "Scaffolding a new React application with SSR, routing, and optional Relay",
178
+ },
179
+ {
180
+ name: "create_domain",
181
+ category: "write",
182
+ use_when: "Scaffolding a new domain module inside an existing application",
183
+ },
184
+ {
185
+ name: "create_route",
186
+ category: "write",
187
+ use_when: "Scaffolding a new route inside an existing application",
188
+ },
189
+ {
190
+ name: "create_wrapper",
191
+ category: "write",
192
+ use_when: "Scaffolding a new wrapper component inside an application",
193
+ },
157
194
 
158
195
  // — Orientation —————————————————————————————————————————————————————————————
159
196
  {
@@ -1,3 +1,4 @@
1
+ import { TOKEN_READ_SURFACE_ENABLED } from "../../token/featureFlag.js";
1
2
  import type { LlmData } from "../types.js";
2
3
 
3
4
  /**
@@ -22,8 +23,11 @@ export default function renderLlmOrientation(data: LlmData): string {
22
23
  lines.push("");
23
24
  lines.push("## Context");
24
25
  lines.push(`tier: ${tierDisplay} | channel: ${ctx.channel}`);
26
+ const tokenCount = TOKEN_READ_SURFACE_ENABLED
27
+ ? `, ${ctx.counts.tokens} tokens`
28
+ : "";
25
29
  lines.push(
26
- `data: ${ctx.counts.blocks} blocks, ${ctx.counts.standards} standards, ${ctx.counts.modifierFamilies} modifier families, ${ctx.counts.tokens} tokens`,
30
+ `data: ${ctx.counts.blocks} blocks, ${ctx.counts.standards} standards, ${ctx.counts.modifierFamilies} modifier families${tokenCount}`,
27
31
  );
28
32
  lines.push(`namespaces: ${ctx.namespaces.join(", ")}`);
29
33
  lines.push("");
@@ -3,6 +3,7 @@ import type { Store } from "@canonical/ke";
3
3
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
4
4
  import { createTestStore, DS_ALL_TTL } from "#testing";
5
5
  import type { PragmaContext } from "../shared/context.js";
6
+ import { TOKEN_READ_SURFACE_ENABLED } from "../token/featureFlag.js";
6
7
  import { buildLlmCommand } from "./commands/index.js";
7
8
  import type { LlmData } from "./types.js";
8
9
 
@@ -72,14 +73,21 @@ describe("buildLlmCommand", () => {
72
73
  expect(value.context.namespaces.length).toBeGreaterThan(0);
73
74
  });
74
75
 
75
- it("includes all 5 decision trees", async () => {
76
+ it("includes all decision trees", async () => {
76
77
  const ctx = makeCtx();
77
78
  const cmd = buildLlmCommand(ctx);
78
79
  const { value, text } = await executeOutput(cmd, ctx);
79
- expect(value.decisionTrees).toHaveLength(5);
80
+ // "Find a token" is gated behind the token read-surface feature flag.
81
+ expect(value.decisionTrees).toHaveLength(
82
+ TOKEN_READ_SURFACE_ENABLED ? 5 : 4,
83
+ );
80
84
  expect(text).toContain("Build a block");
81
85
  expect(text).toContain("Audit standards");
82
- expect(text).toContain("Find a token");
86
+ if (TOKEN_READ_SURFACE_ENABLED) {
87
+ expect(text).toContain("Find a token");
88
+ } else {
89
+ expect(text).not.toContain("Find a token");
90
+ }
83
91
  expect(text).toContain("Explore the design system");
84
92
  expect(text).toContain("Configure");
85
93
  });
@@ -5,6 +5,7 @@
5
5
  import { VERSION } from "#constants";
6
6
  import { buildFilterConfig } from "../../shared/filters/index.js";
7
7
  import type { ToolSpec } from "../../shared/ToolSpec.js";
8
+ import { TOKEN_READ_SURFACE_ENABLED } from "../../token/featureFlag.js";
8
9
  import {
9
10
  COMMAND_REFERENCE,
10
11
  DECISION_TREES,
@@ -43,14 +44,12 @@ function buildCapabilitiesData(): CapabilitiesData {
43
44
  {
44
45
  stage: 2,
45
46
  tool: "*_sample",
46
- purpose:
47
- "Call block_sample, standard_sample, token_sample, or modifier_sample to see real data shapes before querying. Prevents guessing at property names.",
47
+ purpose: `Call block_sample, standard_sample,${TOKEN_READ_SURFACE_ENABLED ? " token_sample," : ""} or modifier_sample to see real data shapes before querying. Prevents guessing at property names.`,
48
48
  },
49
49
  {
50
50
  stage: 3,
51
51
  tool: "domain tools",
52
- purpose:
53
- "Query specific entities — block_list, standard_lookup, token_list, etc. Use the use_when hints above to pick the right tool.",
52
+ purpose: `Query specific entities — block_list, standard_lookup, ${TOKEN_READ_SURFACE_ENABLED ? "token_list, " : ""}etc. Use the use_when hints above to pick the right tool.`,
54
53
  },
55
54
  ],
56
55
  tools: TOOL_CATALOG,
@@ -0,0 +1,64 @@
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 type { FilterConfig } from "../../shared/types/index.js";
5
+ import { TOKEN_READ_SURFACE_ENABLED } from "../../token/featureFlag.js";
6
+ import { renderLlmOrientation } from "../formatters/index.js";
7
+ import type { LlmData } from "../types.js";
8
+ import collectContext from "./collectContext.js";
9
+
10
+ let store: Store;
11
+ let cleanup: () => void;
12
+
13
+ beforeAll(async () => {
14
+ const result = await createTestStore({ ttl: DS_ALL_TTL });
15
+ store = result.store;
16
+ cleanup = result.cleanup;
17
+ });
18
+
19
+ afterAll(() => cleanup());
20
+
21
+ const config: FilterConfig = { tier: undefined, channel: "prerelease" };
22
+
23
+ /** Extract the `## Context` data lines from a rendered orientation doc. */
24
+ function contextBlock(rendered: string): string {
25
+ const lines = rendered.split("\n");
26
+ const start = lines.indexOf("## Context");
27
+ const block: string[] = [];
28
+ for (let i = start + 1; i < lines.length && lines[i] !== ""; i++) {
29
+ block.push(lines[i] ?? "");
30
+ }
31
+ return block.join("\n");
32
+ }
33
+
34
+ describe("collectContext", () => {
35
+ it("assembles counts and namespaces from the store", async () => {
36
+ const ctx = await collectContext(store, config);
37
+
38
+ expect(ctx.tier).toBeUndefined();
39
+ expect(ctx.channel).toBe("prerelease");
40
+ expect(ctx.counts.blocks).toBeGreaterThan(0);
41
+ expect(ctx.counts.standards).toBeGreaterThan(0);
42
+ expect(ctx.counts.modifierFamilies).toBeGreaterThan(0);
43
+ expect(ctx.counts.tokens).toBeGreaterThan(0);
44
+ expect(ctx.namespaces.length).toBeGreaterThan(0);
45
+ });
46
+
47
+ it("renders a stable `## Context` block", async () => {
48
+ const data: LlmData = {
49
+ context: await collectContext(store, config),
50
+ decisionTrees: [],
51
+ commandReference: [],
52
+ };
53
+
54
+ // The token count only renders while the token read surface is enabled.
55
+ const tokenSegment = TOKEN_READ_SURFACE_ENABLED ? ", 2 tokens" : "";
56
+ expect(contextBlock(renderLlmOrientation(data))).toBe(
57
+ [
58
+ "tier: (none) | channel: prerelease",
59
+ `data: 5 blocks, 3 standards, 2 modifier families${tokenSegment}`,
60
+ "namespaces: cs, ds",
61
+ ].join("\n"),
62
+ );
63
+ });
64
+ });
@@ -1,18 +1,16 @@
1
1
  import type { Store } from "@canonical/ke";
2
- import { listBlocks } from "../../block/operations/index.js";
3
- import { listModifiers } from "../../modifier/operations/index.js";
2
+ import { collectEntityCounts } from "../../info/operations/index.js";
4
3
  import { listOntologies } from "../../ontology/operations/index.js";
5
4
  import { resolveTierChain } from "../../shared/filters/buildTierFilter.js";
6
5
  import type { FilterConfig } from "../../shared/types/index.js";
7
- import { listStandards } from "../../standard/operations/index.js";
8
- import { listTokens } from "../../token/operations/index.js";
9
6
  import type { LlmContext } from "../types.js";
10
7
 
11
8
  /**
12
9
  * Collects dynamic context for the `pragma llm` orientation output.
13
10
  *
14
- * Queries the store in parallel for block, standard, modifier, token, and
15
- * ontology counts, and combines them with tier/channel config state.
11
+ * Queries the store in parallel for entity counts (via
12
+ * {@link collectEntityCounts}) and ontology namespaces, and combines them
13
+ * with tier/channel config state.
16
14
  *
17
15
  * @note Queries ke store
18
16
  *
@@ -24,11 +22,8 @@ export default async function collectContext(
24
22
  store: Store,
25
23
  config: FilterConfig,
26
24
  ): Promise<LlmContext> {
27
- const [blocks, standards, modifiers, tokens, ontologies] = await Promise.all([
28
- listBlocks(store, config),
29
- listStandards(store),
30
- listModifiers(store),
31
- listTokens(store),
25
+ const [counts, ontologies] = await Promise.all([
26
+ collectEntityCounts(store, config),
32
27
  listOntologies(store),
33
28
  ]);
34
29
 
@@ -36,12 +31,7 @@ export default async function collectContext(
36
31
  tier: config.tier,
37
32
  tierChain: resolveTierChain(config.tier),
38
33
  channel: config.channel,
39
- counts: {
40
- blocks: blocks.length,
41
- standards: standards.length,
42
- modifierFamilies: modifiers.length,
43
- tokens: tokens.length,
44
- },
34
+ counts,
45
35
  namespaces: ontologies.map((o) => o.prefix),
46
36
  };
47
37
  }
@@ -1,42 +1,9 @@
1
- /**
2
- * Wires the `pragma modifier list` CLI command.
3
- *
4
- * Lists all modifier families with their allowed values. Throws a
5
- * structured recovery error when no families are found.
6
- */
7
-
8
- import {
9
- type CommandDefinition,
10
- createOutputResult,
11
- } from "@canonical/cli-core";
12
- import { createListView } from "#tui";
1
+ import type { CommandDefinition } from "@canonical/cli-core";
13
2
  import type { PragmaContext } from "../../shared/context.js";
14
- import { selectFormatter } from "../../shared/formatters.js";
15
- import { listFormatters } from "../formatters/index.js";
16
- import { modifierConfig } from "../modifierConfig.js";
17
- import { resolveModifierList } from "../orchestration/index.js";
3
+ import { compileReadCommand } from "../../shared/stories/index.js";
4
+ import { modifierListStory } from "../stories.js";
18
5
 
6
+ /** Wire the `pragma modifier list` CLI command from the modifier list story. */
19
7
  export default function listCommand(ctx: PragmaContext): CommandDefinition {
20
- return {
21
- path: ["modifier", "list"],
22
- description: "List all modifier families",
23
- parameters: [],
24
- meta: {
25
- examples: ["pragma modifier list", "pragma modifier list --llm"],
26
- },
27
- async execute() {
28
- const resolution = await resolveModifierList(ctx);
29
-
30
- return createOutputResult([...resolution.items], {
31
- plain: selectFormatter(ctx, listFormatters),
32
- ink: (data) =>
33
- createListView({
34
- heading: "Modifiers",
35
- domain: "modifier",
36
- items: data,
37
- columns: modifierConfig.listColumns,
38
- }),
39
- });
40
- },
41
- };
8
+ return compileReadCommand(ctx, modifierListStory);
42
9
  }
@@ -1,85 +1,14 @@
1
- /**
2
- * Wires the `pragma modifier lookup <name...>` CLI command.
3
- *
4
- * Retrieves a single modifier family by name and renders its values.
5
- */
6
-
7
- import {
8
- type CommandDefinition,
9
- createOutputResult,
10
- } from "@canonical/cli-core";
11
- import { createLookupView } from "#tui";
1
+ import type { CommandDefinition } from "@canonical/cli-core";
12
2
  import type { PragmaContext } from "../../shared/context.js";
13
- import type { LookupResult } from "../../shared/contracts.js";
14
- import { renderLookupResults } from "../../shared/formatters.js";
15
- import {
16
- createInkLookupOptions,
17
- lookupFormatters,
18
- } from "../formatters/index.js";
19
- import type { lookupModifier } from "../operations/index.js";
20
- import { resolveModifierLookup } from "../orchestration/index.js";
21
-
22
- interface ModifierLookupOutput {
23
- readonly result: LookupResult<Awaited<ReturnType<typeof lookupModifier>>>;
24
- }
3
+ import { compileLookupCommand } from "../../shared/stories/index.js";
4
+ import { modifierLookupStory } from "../stories.js";
25
5
 
6
+ /**
7
+ * Wire the `pragma modifier lookup <name...>` CLI command from the
8
+ * modifier lookup story.
9
+ */
26
10
  export default function buildLookupCommand(
27
11
  ctx: PragmaContext,
28
12
  ): CommandDefinition {
29
- return {
30
- path: ["modifier", "lookup"],
31
- description: "Look up a modifier family and its values",
32
- parameters: [
33
- {
34
- name: "names",
35
- description: "Modifier family names or IRIs",
36
- type: "multiselect",
37
- positional: true,
38
- required: true,
39
- },
40
- ],
41
- meta: {
42
- examples: [
43
- "pragma modifier lookup importance",
44
- "pragma modifier lookup importance density",
45
- "pragma modifier lookup importance --llm",
46
- ],
47
- },
48
- async execute(params: Record<string, unknown>) {
49
- const names = normalizeNames(params.names, params.name);
50
- const contract = await resolveModifierLookup(ctx.store, names);
51
-
52
- return createOutputResult<ModifierLookupOutput>(
53
- { result: contract.result },
54
- {
55
- plain: ({ result }) =>
56
- renderLookupResults({
57
- ctx,
58
- result,
59
- formatters: lookupFormatters,
60
- mapResult: (family) => family,
61
- }),
62
- ink: ({ result }) =>
63
- createLookupView({
64
- results: result.results,
65
- errors: result.errors,
66
- domain: "modifier",
67
- options: createInkLookupOptions(),
68
- }),
69
- },
70
- );
71
- },
72
- };
73
- }
74
-
75
- function normalizeNames(names: unknown, legacyName?: unknown): string[] {
76
- if (Array.isArray(names)) {
77
- return names.filter(
78
- (name): name is string => typeof name === "string" && name.length > 0,
79
- );
80
- }
81
- if (typeof legacyName === "string" && legacyName.length > 0) {
82
- return [legacyName];
83
- }
84
- return [];
13
+ return compileLookupCommand(ctx, modifierLookupStory);
85
14
  }
@@ -11,6 +11,7 @@ import {
11
11
  } from "@canonical/cli-core";
12
12
  import type { PragmaContext } from "../../shared/context.js";
13
13
  import { selectFormatter } from "../../shared/formatters.js";
14
+ import parseSampleCount from "../../shared/parseSampleCount.js";
14
15
  import type { ModifierFamily, SampleOutput } from "../../shared/types/index.js";
15
16
  import { sampleFormatters } from "../formatters/index.js";
16
17
  import { sampleModifiers } from "../operations/index.js";
@@ -37,7 +38,7 @@ export default function sampleCommand(ctx: PragmaContext): CommandDefinition {
37
38
  examples: ["pragma modifier sample", "pragma modifier sample --count 3"],
38
39
  },
39
40
  async execute(params) {
40
- const count = Number(params.count ?? 2);
41
+ const count = parseSampleCount(params.count);
41
42
  const result = await sampleModifiers(ctx.store, count);
42
43
 
43
44
  const output: SampleOutput<ModifierFamily> = {
@@ -1,99 +1,25 @@
1
1
  /**
2
- * MCP tool specs for the modifier domain.
2
+ * MCP tool specs for the modifier domain — modifier_list, modifier_lookup,
3
+ * modifier_sample.
3
4
  *
4
- * Declarative definitions — no MCP imports. The adapter layer
5
- * converts these into registered MCP tools via `registerFromSpec()`.
5
+ * The list and lookup tools are compiled from the modifier read stories in
6
+ * `../stories.ts`; only the sample tool is spec'd by hand. The adapter
7
+ * layer converts these into registered MCP tools via `registerFromSpec()`.
6
8
  */
7
9
 
8
- import type { ToolSpec } from "../../shared/ToolSpec.js";
9
10
  import {
10
- listFormatters as modifierListFmt,
11
- lookupFormatters as modifierLookupFmt,
12
- sampleFormatters as modifierSampleFmt,
13
- } from "../formatters/index.js";
11
+ compileLookupTool,
12
+ compileReadTool,
13
+ condense,
14
+ } from "../../shared/stories/index.js";
15
+ import type { ToolSpec } from "../../shared/ToolSpec.js";
16
+ import { sampleFormatters as modifierSampleFmt } from "../formatters/index.js";
14
17
  import { sampleModifiers } from "../operations/index.js";
15
- import {
16
- resolveModifierList,
17
- resolveModifierLookup,
18
- } from "../orchestration/index.js";
18
+ import { modifierListStory, modifierLookupStory } from "../stories.js";
19
19
 
20
20
  const specs: readonly ToolSpec[] = [
21
- {
22
- name: "modifier_list",
23
- description: "List all modifier families with their values.",
24
- params: {
25
- condensed: {
26
- type: "boolean",
27
- description: "Token-optimized output",
28
- optional: true,
29
- },
30
- },
31
- readOnly: true,
32
- async execute(rt, { condensed }) {
33
- const resolution = await resolveModifierList(rt);
34
-
35
- if (condensed) {
36
- const text = modifierListFmt.llm([...resolution.items]);
37
- return {
38
- condensed: true,
39
- text,
40
- tokens: `~${Math.ceil(text.length / 4)}`,
41
- };
42
- }
43
-
44
- return {
45
- data: resolution.items,
46
- meta: { count: resolution.items.length },
47
- };
48
- },
49
- },
50
-
51
- {
52
- name: "modifier_lookup",
53
- description: "Get one or more modifier families and their values.",
54
- params: {
55
- names: {
56
- type: "string[]",
57
- description: "Modifier family names or IRIs to look up",
58
- optional: false,
59
- },
60
- condensed: {
61
- type: "boolean",
62
- description: "Token-optimized output",
63
- optional: true,
64
- },
65
- },
66
- readOnly: true,
67
- async execute(rt, { names, condensed }) {
68
- const contract = await resolveModifierLookup(rt.store, names as string[]);
69
- const result = contract.result;
70
-
71
- if (condensed) {
72
- const textParts = result.results.map((family) =>
73
- modifierLookupFmt.llm(family),
74
- );
75
-
76
- if (result.errors.length > 0) {
77
- textParts.push(
78
- [
79
- "### Errors",
80
- ...result.errors.map(
81
- (error) => `- ${error.query}: ${error.message}`,
82
- ),
83
- ].join("\n"),
84
- );
85
- }
86
-
87
- return {
88
- condensed: true,
89
- text: textParts.join("\n\n"),
90
- tokens: `~${Math.ceil(textParts.join("\n\n").length / 4)}`,
91
- };
92
- }
93
-
94
- return { data: result, meta: { count: result.results.length } };
95
- },
96
- },
21
+ compileReadTool(modifierListStory),
22
+ compileLookupTool(modifierLookupStory),
97
23
  {
98
24
  name: "modifier_sample",
99
25
  description:
@@ -121,12 +47,7 @@ const specs: readonly ToolSpec[] = [
121
47
  ];
122
48
 
123
49
  if (condensed) {
124
- const text = modifierSampleFmt.llm({ ...result, nextSteps });
125
- return {
126
- condensed: true,
127
- text,
128
- tokens: `~${Math.ceil(text.length / 4)}`,
129
- };
50
+ return condense(modifierSampleFmt.llm({ ...result, nextSteps }));
130
51
  }
131
52
 
132
53
  return {
@@ -28,7 +28,7 @@ export default async function lookupModifier(
28
28
 
29
29
  const result = await store.query(
30
30
  buildQuery(`
31
- SELECT ?family (GROUP_CONCAT(DISTINCT ?valueName; separator="|") AS ?values)
31
+ SELECT ?family ?familyName (GROUP_CONCAT(DISTINCT ?valueName; separator="|") AS ?values)
32
32
  WHERE {
33
33
  ?family a ${P.ds}ModifierFamily ;
34
34
  ${P.ds}name ?familyName .
@@ -39,7 +39,7 @@ export default async function lookupModifier(
39
39
  ${P.ds}name ?valueName .
40
40
  }
41
41
  }
42
- GROUP BY ?family
42
+ GROUP BY ?family ?familyName
43
43
  `),
44
44
  );
45
45
 
@@ -61,7 +61,9 @@ export default async function lookupModifier(
61
61
  const b = result.bindings[0] as (typeof result.bindings)[number];
62
62
  return {
63
63
  uri: (b.family ?? "") as URI,
64
- name,
64
+ // Return the canonical stored name, not the raw user query (which may
65
+ // differ in casing).
66
+ name: b.familyName ?? name,
65
67
  values: b.values ? b.values.split("|").filter(Boolean) : [],
66
68
  };
67
69
  }
@@ -18,11 +18,12 @@ export default async function resolveModifierLookup(
18
18
  const lookupResult: LookupResult<ModifierFamily> =
19
19
  names.length > 0
20
20
  ? await lookupMany(names, (query) => lookupModifier(store, query))
21
- : { results: [], errors: [] };
21
+ : { results: [], errors: [], meta: { internalErrorCount: 0 } };
22
22
 
23
23
  const result: LookupResult<ModifierFamily> = {
24
24
  results: lookupResult.results,
25
25
  errors: [...lookupResult.errors, ...globErrors],
26
+ meta: lookupResult.meta ?? { internalErrorCount: 0 },
26
27
  };
27
28
 
28
29
  return {
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { modifierListStory, modifierLookupStory } from "./stories.js";
3
+
4
+ describe("modifierListStory", () => {
5
+ it("renders the ink list view", () => {
6
+ const view = modifierListStory.renderInk?.([]);
7
+ expect(typeof view).toBe("string");
8
+ expect(view).toContain("Modifiers");
9
+ });
10
+ });
11
+
12
+ describe("modifierLookupStory", () => {
13
+ it("renders the ink lookup view", () => {
14
+ const view = modifierLookupStory.renderInk?.(
15
+ { results: [], errors: [] },
16
+ { surface: "cli", detailed: false, params: {} },
17
+ );
18
+ expect(typeof view).toBe("string");
19
+ });
20
+ });