@canonical/pragma-cli 0.27.1-experimental.0 → 0.30.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 (344) hide show
  1. package/README.md +67 -15
  2. package/dist/pragma +0 -0
  3. package/package.json +16 -17
  4. package/src/config/defaultConfig.test.ts +33 -0
  5. package/src/config/defaultConfig.ts +59 -0
  6. package/src/config/defaults.json +17 -0
  7. package/src/config/findProjectConfigPath.test.ts +53 -0
  8. package/src/config/findProjectConfigPath.ts +36 -0
  9. package/src/config/index.ts +17 -2
  10. package/src/config/mergeConfigFileUpdate.ts +58 -0
  11. package/src/config/parseConfigValues.ts +215 -0
  12. package/src/config/readConfig.test.ts +104 -13
  13. package/src/config/readConfig.ts +12 -117
  14. package/src/config/readConfigLayers.test.ts +107 -0
  15. package/src/config/readConfigLayers.ts +115 -0
  16. package/src/config/resolveGlobalConfigPath.ts +13 -0
  17. package/src/config/resolveWriteConfigPath.test.ts +53 -0
  18. package/src/config/resolveWriteConfigPath.ts +31 -0
  19. package/src/config/types.ts +88 -2
  20. package/src/config/writeConfig.ts +25 -43
  21. package/src/constants.ts +12 -1
  22. package/src/domains/block/commands/index.ts +2 -1
  23. package/src/domains/block/commands/list.ts +5 -90
  24. package/src/domains/block/commands/lookup.ts +8 -167
  25. package/src/domains/block/commands/sample.ts +55 -0
  26. package/src/domains/block/formatters/index.ts +2 -1
  27. package/src/domains/block/formatters/sample.ts +21 -0
  28. package/src/domains/block/index.ts +3 -3
  29. package/src/domains/block/mcp/specs.ts +36 -168
  30. package/src/domains/block/operations/index.ts +2 -1
  31. package/src/domains/block/operations/lookup.ts +9 -0
  32. package/src/domains/block/operations/sample.ts +41 -0
  33. package/src/domains/block/orchestration/blockEmptyError.test.ts +26 -0
  34. package/src/domains/block/orchestration/resolveBlockLookup.ts +11 -3
  35. package/src/domains/block/stories.test.ts +28 -0
  36. package/src/domains/block/stories.ts +254 -0
  37. package/src/domains/config/commands/channel.test.ts +14 -3
  38. package/src/domains/config/commands/channel.ts +11 -7
  39. package/src/domains/config/commands/configScope.ts +46 -0
  40. package/src/domains/config/commands/framework.test.ts +105 -0
  41. package/src/domains/config/commands/framework.ts +91 -0
  42. package/src/domains/config/commands/index.ts +2 -0
  43. package/src/domains/config/commands/show.ts +5 -45
  44. package/src/domains/config/commands/tier.test.ts +13 -2
  45. package/src/domains/config/commands/tier.ts +11 -7
  46. package/src/domains/config/commands/trace.test.ts +165 -0
  47. package/src/domains/config/commands/trace.ts +83 -0
  48. package/src/domains/config/formatters/channel.test.ts +20 -6
  49. package/src/domains/config/formatters/channel.ts +14 -11
  50. package/src/domains/config/formatters/framework.ts +37 -0
  51. package/src/domains/config/formatters/index.ts +2 -0
  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 +28 -0
  57. package/src/domains/config/index.ts +15 -2
  58. package/src/domains/config/mcp/specs.ts +33 -53
  59. package/src/domains/config/operations/index.ts +1 -0
  60. package/src/domains/config/operations/show.test.ts +18 -0
  61. package/src/domains/config/operations/show.ts +7 -1
  62. package/src/domains/config/operations/types.ts +7 -0
  63. package/src/domains/config/operations/validateFramework.ts +24 -0
  64. package/src/domains/config/stories.ts +42 -0
  65. package/src/domains/config/tasks/index.ts +3 -0
  66. package/src/domains/config/tasks/setChannel.ts +13 -22
  67. package/src/domains/config/tasks/setFramework.ts +21 -0
  68. package/src/domains/config/tasks/setTier.ts +10 -23
  69. package/src/domains/config/tasks/setTrace.ts +20 -0
  70. package/src/domains/config/tasks/writeConfigField.ts +41 -0
  71. package/src/domains/create/commands/component.ts +5 -5
  72. package/src/domains/doctor/operations/checks/checkConfigFile.ts +19 -5
  73. package/src/domains/doctor/operations/checks/checkKeStore.ts +5 -5
  74. package/src/domains/doctor/operations/checks/checkMcpCommands.ts +130 -0
  75. package/src/domains/doctor/operations/checks/checkMcpConfigured.ts +1 -1
  76. package/src/domains/doctor/operations/checks/checkPackageRefs.ts +30 -48
  77. package/src/domains/doctor/operations/checks/checkSkillsSymlinked.ts +1 -1
  78. package/src/domains/doctor/operations/checks/index.ts +1 -0
  79. package/src/domains/doctor/operations/checks.test.ts +162 -8
  80. package/src/domains/doctor/operations/runChecks.test.ts +85 -4
  81. package/src/domains/doctor/operations/runChecks.ts +50 -12
  82. package/src/domains/graph/helpers/resolveUri.test.ts +50 -0
  83. package/src/domains/graph/helpers/resolveUri.ts +28 -21
  84. package/src/domains/graphql/commands/build.test.ts +196 -0
  85. package/src/domains/graphql/commands/build.ts +117 -0
  86. package/src/domains/graphql/commands/check.test.ts +141 -0
  87. package/src/domains/graphql/commands/check.ts +81 -0
  88. package/src/domains/graphql/commands/index.ts +5 -0
  89. package/src/domains/graphql/commands/serve.test.ts +40 -0
  90. package/src/domains/graphql/commands/serve.ts +131 -0
  91. package/src/domains/graphql/constants.ts +10 -0
  92. package/src/domains/graphql/formatters/index.ts +3 -0
  93. package/src/domains/graphql/formatters/report.ts +78 -0
  94. package/src/domains/graphql/helpers/gatherSources.test.ts +92 -0
  95. package/src/domains/graphql/helpers/gatherSources.ts +58 -0
  96. package/src/domains/graphql/helpers/index.ts +6 -0
  97. package/src/domains/graphql/helpers/parsePrefixes.test.ts +44 -0
  98. package/src/domains/graphql/helpers/parsePrefixes.ts +38 -0
  99. package/src/domains/graphql/helpers/resolveSourceFiles.test.ts +56 -0
  100. package/src/domains/graphql/helpers/resolveSourceFiles.ts +45 -0
  101. package/src/domains/graphql/helpers/routeGraphql.test.ts +43 -0
  102. package/src/domains/graphql/helpers/routeGraphql.ts +28 -0
  103. package/src/domains/graphql/index.ts +24 -0
  104. package/src/domains/graphql/operations/compileSchema.test.ts +95 -0
  105. package/src/domains/graphql/operations/compileSchema.ts +107 -0
  106. package/src/domains/graphql/operations/createSchemaServer.test.ts +50 -0
  107. package/src/domains/graphql/operations/createSchemaServer.ts +75 -0
  108. package/src/domains/graphql/operations/index.ts +12 -0
  109. package/src/domains/graphql/types.ts +29 -0
  110. package/src/domains/info/operations/collectInfo.test.ts +16 -5
  111. package/src/domains/info/operations/collectInfo.ts +16 -19
  112. package/src/domains/llm/capabilities.test.ts +91 -0
  113. package/src/domains/llm/commands/capabilities.ts +28 -0
  114. package/src/domains/llm/commands/index.ts +1 -0
  115. package/src/domains/llm/data/commandReference.ts +90 -18
  116. package/src/domains/llm/data/decisionTrees.ts +15 -13
  117. package/src/domains/llm/data/index.ts +2 -0
  118. package/src/domains/llm/data/toolCatalog.ts +190 -0
  119. package/src/domains/llm/formatters/capabilities.ts +50 -0
  120. package/src/domains/llm/formatters/index.ts +1 -0
  121. package/src/domains/llm/index.ts +3 -2
  122. package/src/domains/llm/mcp/index.ts +1 -1
  123. package/src/domains/llm/mcp/specs.ts +59 -52
  124. package/src/domains/llm/types.ts +40 -0
  125. package/src/domains/modifier/commands/index.ts +2 -1
  126. package/src/domains/modifier/commands/list.ts +5 -38
  127. package/src/domains/modifier/commands/lookup.ts +8 -79
  128. package/src/domains/modifier/commands/sample.ts +53 -0
  129. package/src/domains/modifier/formatters/index.ts +2 -1
  130. package/src/domains/modifier/formatters/sample.ts +15 -0
  131. package/src/domains/modifier/index.ts +7 -3
  132. package/src/domains/modifier/mcp/specs.ts +38 -70
  133. package/src/domains/modifier/operations/index.ts +2 -1
  134. package/src/domains/modifier/operations/lookup.ts +9 -0
  135. package/src/domains/modifier/operations/sample.ts +32 -0
  136. package/src/domains/modifier/orchestration/modifierEmptyError.test.ts +26 -0
  137. package/src/domains/modifier/orchestration/modifierEmptyError.ts +7 -2
  138. package/src/domains/modifier/orchestration/resolveModifierLookup.ts +15 -2
  139. package/src/domains/modifier/stories.test.ts +20 -0
  140. package/src/domains/modifier/stories.ts +77 -0
  141. package/src/domains/ontology/commands/list.ts +5 -58
  142. package/src/domains/ontology/commands/show.ts +6 -58
  143. package/src/domains/ontology/formatters/show.ts +7 -1
  144. package/src/domains/ontology/mcp/specs.ts +7 -84
  145. package/src/domains/ontology/stories.test.ts +36 -0
  146. package/src/domains/ontology/stories.ts +108 -0
  147. package/src/domains/refs/operations/index.ts +1 -1
  148. package/src/domains/refs/operations/paths.ts +29 -1
  149. package/src/domains/refs/operations/updateRefs.test.ts +6 -3
  150. package/src/domains/refs/operations/updateRefs.ts +2 -36
  151. package/src/domains/setup/commands/skills.test.ts +6 -2
  152. package/src/domains/setup/commands/skills.ts +6 -2
  153. package/src/domains/setup/helpers/runSetupTask.test.ts +148 -150
  154. package/src/domains/setup/helpers/runSetupTask.ts +62 -70
  155. package/src/domains/setup/operations/setupMcp.test.ts +6 -1
  156. package/src/domains/shared/bootStore.ts +92 -50
  157. package/src/domains/shared/compactUri.test.ts +11 -0
  158. package/src/domains/shared/compactUri.ts +10 -5
  159. package/src/domains/shared/context.ts +2 -2
  160. package/src/domains/shared/contracts.ts +12 -0
  161. package/src/domains/shared/createInteractivePromptSession.test.ts +439 -0
  162. package/src/domains/shared/createInteractivePromptSession.ts +236 -0
  163. package/src/domains/shared/emptyErrorRecovery.test.ts +109 -0
  164. package/src/domains/shared/loaders/bundledLoader.test.ts +248 -0
  165. package/src/domains/shared/loaders/bundledLoader.ts +206 -0
  166. package/src/domains/shared/loaders/gitLoader.ts +31 -0
  167. package/src/domains/shared/loaders/index.ts +9 -0
  168. package/src/domains/shared/loaders/localLoader.ts +87 -0
  169. package/src/domains/shared/loaders/readPackageDir.ts +147 -0
  170. package/src/domains/shared/loaders/storyAssetsPlugin.test.ts +84 -0
  171. package/src/domains/shared/loaders/storyAssetsPlugin.ts +46 -0
  172. package/src/domains/shared/lookupMany.test.ts +120 -0
  173. package/src/domains/shared/lookupMany.ts +43 -3
  174. package/src/domains/shared/mergeAndParseRefs.test.ts +89 -0
  175. package/src/domains/shared/mergeAndParseRefs.ts +44 -0
  176. package/src/domains/shared/packages.ts +14 -120
  177. package/src/domains/shared/pickRandom.ts +22 -0
  178. package/src/domains/shared/resolveConfiguredGraphs.test.ts +27 -0
  179. package/src/domains/shared/resolveConfiguredGraphs.ts +41 -0
  180. package/src/domains/shared/runtime.ts +7 -63
  181. package/src/domains/shared/sampleFormatters.ts +47 -0
  182. package/src/domains/shared/semanticPackage.ts +112 -0
  183. package/src/domains/shared/stories/compileLookupCommand.test.ts +145 -0
  184. package/src/domains/shared/stories/compileLookupCommand.ts +100 -0
  185. package/src/domains/shared/stories/compileLookupTool.test.ts +105 -0
  186. package/src/domains/shared/stories/compileLookupTool.ts +96 -0
  187. package/src/domains/shared/stories/compileReadCommand.test.ts +121 -0
  188. package/src/domains/shared/stories/compileReadCommand.ts +48 -0
  189. package/src/domains/shared/stories/compileReadTool.test.ts +64 -0
  190. package/src/domains/shared/stories/compileReadTool.ts +38 -0
  191. package/src/domains/shared/stories/condense.test.ts +18 -0
  192. package/src/domains/shared/stories/condense.ts +15 -0
  193. package/src/domains/shared/stories/index.ts +20 -0
  194. package/src/domains/shared/stories/normalizeNames.test.ts +20 -0
  195. package/src/domains/shared/stories/normalizeNames.ts +22 -0
  196. package/src/domains/shared/stories/pack/applyPackFilters.test.ts +102 -0
  197. package/src/domains/shared/stories/pack/applyPackFilters.ts +76 -0
  198. package/src/domains/shared/stories/pack/buildLookupQuery.test.ts +51 -0
  199. package/src/domains/shared/stories/pack/buildLookupQuery.ts +80 -0
  200. package/src/domains/shared/stories/pack/collectPackStories.test.ts +108 -0
  201. package/src/domains/shared/stories/pack/collectPackStories.ts +76 -0
  202. package/src/domains/shared/stories/pack/compilePackCommands.ts +40 -0
  203. package/src/domains/shared/stories/pack/compilePackStories.test.ts +146 -0
  204. package/src/domains/shared/stories/pack/compilePackStories.ts +253 -0
  205. package/src/domains/shared/stories/pack/compilePackToolSpecs.ts +43 -0
  206. package/src/domains/shared/stories/pack/index.ts +28 -0
  207. package/src/domains/shared/stories/pack/runSelectQuery.ts +31 -0
  208. package/src/domains/shared/stories/pack/standardParity.test.ts +308 -0
  209. package/src/domains/shared/stories/pack/types.ts +104 -0
  210. package/src/domains/shared/stories/pack/validateStoryPackDefinition.test.ts +240 -0
  211. package/src/domains/shared/stories/pack/validateStoryPackDefinition.ts +408 -0
  212. package/src/domains/shared/stories/projectCliParameters.test.ts +59 -0
  213. package/src/domains/shared/stories/projectCliParameters.ts +57 -0
  214. package/src/domains/shared/stories/projectToolParams.test.ts +50 -0
  215. package/src/domains/shared/stories/projectToolParams.ts +32 -0
  216. package/src/domains/shared/stories/requirePragmaContext.test.ts +23 -0
  217. package/src/domains/shared/stories/requirePragmaContext.ts +23 -0
  218. package/src/domains/shared/stories/resolveLookupDetailed.test.ts +57 -0
  219. package/src/domains/shared/stories/resolveLookupDetailed.ts +27 -0
  220. package/src/domains/shared/stories/types.ts +171 -0
  221. package/src/domains/shared/suggestions/detectCrossDomain.test.ts +43 -0
  222. package/src/domains/shared/suggestions/detectCrossDomain.ts +116 -0
  223. package/src/domains/shared/suggestions/expandGlob.test.ts +92 -0
  224. package/src/domains/shared/suggestions/expandGlob.ts +52 -0
  225. package/src/domains/shared/suggestions/expandLookupQueries.ts +57 -0
  226. package/src/domains/shared/suggestions/index.ts +7 -0
  227. package/src/domains/shared/suggestions/listDomainNames.ts +61 -0
  228. package/src/domains/shared/suggestions/suggestNames.test.ts +70 -0
  229. package/src/domains/shared/suggestions/suggestNames.ts +130 -0
  230. package/src/domains/shared/types/index.ts +1 -0
  231. package/src/domains/shared/types/runtime.ts +4 -1
  232. package/src/domains/shared/types/sample.ts +17 -0
  233. package/src/domains/skill/commands/index.ts +3 -1
  234. package/src/domains/skill/commands/list.test.ts +6 -2
  235. package/src/domains/skill/commands/list.ts +5 -63
  236. package/src/domains/skill/commands/lookup.test.ts +118 -0
  237. package/src/domains/skill/commands/lookup.ts +14 -0
  238. package/src/domains/skill/formatters/index.ts +1 -0
  239. package/src/domains/skill/formatters/lookup.test.ts +46 -0
  240. package/src/domains/skill/formatters/lookup.ts +57 -0
  241. package/src/domains/skill/helpers/resolveSkillSources.ts +48 -16
  242. package/src/domains/skill/index.ts +7 -3
  243. package/src/domains/skill/mcp/specs.ts +10 -29
  244. package/src/domains/skill/operations/discover.test.ts +61 -30
  245. package/src/domains/skill/operations/discover.ts +28 -37
  246. package/src/domains/skill/operations/index.ts +2 -1
  247. package/src/domains/skill/operations/list.test.ts +15 -7
  248. package/src/domains/skill/operations/lookup.test.ts +91 -0
  249. package/src/domains/skill/operations/lookup.ts +70 -0
  250. package/src/domains/skill/stories.test.ts +43 -0
  251. package/src/domains/skill/stories.ts +103 -0
  252. package/src/domains/skill/types.ts +8 -0
  253. package/src/domains/standard/commands/index.ts +2 -1
  254. package/src/domains/standard/commands/list.ts +5 -84
  255. package/src/domains/standard/commands/lookup.ts +8 -93
  256. package/src/domains/standard/commands/sample.ts +57 -0
  257. package/src/domains/standard/formatters/index.ts +2 -1
  258. package/src/domains/standard/formatters/sample.ts +15 -0
  259. package/src/domains/standard/index.ts +8 -1
  260. package/src/domains/standard/mcp/specs.ts +44 -152
  261. package/src/domains/standard/operations/index.ts +2 -1
  262. package/src/domains/standard/operations/lookup.ts +9 -0
  263. package/src/domains/standard/operations/sample.ts +35 -0
  264. package/src/domains/standard/orchestration/resolveStandardLookup.ts +15 -2
  265. package/src/domains/standard/orchestration/standardEmptyError.test.ts +33 -0
  266. package/src/domains/standard/orchestration/standardEmptyError.ts +16 -6
  267. package/src/domains/standard/stories.test.ts +24 -0
  268. package/src/domains/standard/stories.ts +151 -0
  269. package/src/domains/tier/commands/list.ts +5 -55
  270. package/src/domains/tier/mcp/specs.ts +5 -31
  271. package/src/domains/tier/stories.test.ts +22 -0
  272. package/src/domains/tier/stories.ts +52 -0
  273. package/src/domains/token/commands/index.ts +2 -1
  274. package/src/domains/token/commands/sample.ts +53 -0
  275. package/src/domains/token/formatters/index.ts +2 -1
  276. package/src/domains/token/formatters/sample.ts +16 -0
  277. package/src/domains/token/index.ts +8 -1
  278. package/src/domains/token/mcp/specs.ts +52 -2
  279. package/src/domains/token/operations/index.ts +2 -1
  280. package/src/domains/token/operations/lookup.ts +9 -0
  281. package/src/domains/token/operations/sample.ts +32 -0
  282. package/src/domains/token/orchestration/resolveTokenLookup.ts +15 -2
  283. package/src/domains/token/orchestration/tokenEmptyError.test.ts +33 -0
  284. package/src/domains/token/orchestration/tokenEmptyError.ts +5 -2
  285. package/src/domains/trace/commands/clear.ts +71 -0
  286. package/src/domains/trace/commands/index.ts +5 -0
  287. package/src/domains/trace/commands/sessions.ts +32 -0
  288. package/src/domains/trace/commands/show.ts +145 -0
  289. package/src/domains/trace/formatters/index.ts +9 -0
  290. package/src/domains/trace/formatters/sessions.ts +80 -0
  291. package/src/domains/trace/formatters/show.ts +122 -0
  292. package/src/domains/trace/index.ts +17 -0
  293. package/src/domains/trace/operations/index.ts +8 -0
  294. package/src/domains/trace/operations/listSessions.test.ts +55 -0
  295. package/src/domains/trace/operations/listSessions.ts +52 -0
  296. package/src/domains/trace/operations/readTraceLog.test.ts +100 -0
  297. package/src/domains/trace/operations/readTraceLog.ts +104 -0
  298. package/src/domains/trace/tracePlugin.test.ts +171 -0
  299. package/src/domains/trace/tracePlugin.ts +159 -0
  300. package/src/domains/trace/types.ts +65 -0
  301. package/src/error/PragmaError.ts +15 -2
  302. package/src/error/types.ts +15 -1
  303. package/src/mcp/error/serializeErrorPayload.ts +7 -0
  304. package/src/mcp/error/types.ts +8 -0
  305. package/src/mcp/registerResources.test.ts +405 -75
  306. package/src/mcp/registerResources.ts +5 -299
  307. package/src/mcp/resources/buildGraphIndex.ts +167 -0
  308. package/src/mcp/resources/buildResourceList.test.ts +97 -0
  309. package/src/mcp/resources/buildResourceList.ts +176 -0
  310. package/src/mcp/resources/classifyEntity.test.ts +40 -0
  311. package/src/mcp/resources/classifyEntity.ts +27 -0
  312. package/src/mcp/resources/constants.ts +105 -0
  313. package/src/mcp/resources/displayPredicates.ts +62 -0
  314. package/src/mcp/resources/pickFirstValue.test.ts +29 -0
  315. package/src/mcp/resources/pickFirstValue.ts +26 -0
  316. package/src/mcp/resources/pickPrimaryType.test.ts +41 -0
  317. package/src/mcp/resources/pickPrimaryType.ts +26 -0
  318. package/src/mcp/resources/rankUriCompletions.test.ts +52 -0
  319. package/src/mcp/resources/rankUriCompletions.ts +64 -0
  320. package/src/mcp/resources/readEntity.ts +169 -0
  321. package/src/mcp/resources/registerResources.ts +126 -0
  322. package/src/mcp/resources/types.ts +128 -0
  323. package/src/mcp/tools/index.ts +9 -0
  324. package/src/mcp/tools/registerTools.test.ts +84 -12
  325. package/src/mcp/types.ts +4 -0
  326. package/src/mcp/utils/wrapTool.test.ts +1 -0
  327. package/src/pipeline/collectCommands.ts +15 -2
  328. package/src/pipeline/renderError.ts +15 -0
  329. package/src/pipeline/resolveCommandKind.ts +8 -1
  330. package/src/pipeline/runCli.ts +51 -6
  331. package/src/testing/createTestMcpClient.ts +5 -1
  332. package/src/testing/graphqlFixtures.ts +72 -0
  333. package/src/testing/index.ts +17 -0
  334. package/src/testing/integration/__snapshots__/executor-golden.test.ts.snap +1207 -0
  335. package/src/testing/integration/cross-binary-byte-equality.test.ts +129 -0
  336. package/src/testing/integration/executor-execution.test.ts +101 -0
  337. package/src/testing/integration/executor-golden.test.ts +145 -0
  338. package/src/testing/integration/mcp-surface.test.ts +11 -5
  339. package/src/testing/integration/parity.test.ts +17 -12
  340. package/src/testing/regression/0001-skill-discovery-granularity.test.ts +71 -0
  341. package/src/testing/setupXdgIsolation.ts +15 -0
  342. package/src/testing/standardParityFixtures.ts +92 -0
  343. package/src/testing/storyFixtures.ts +63 -0
  344. package/src/pipeline/runInteractiveCommand.ts +0 -198
@@ -1,6 +1,6 @@
1
1
  import { beforeEach, describe, expect, it, vi } from "vitest";
2
2
 
3
- const readConfigMock = vi.fn();
3
+ const readConfigLayersMock = vi.fn();
4
4
  const detectInstallSourceMock = vi.fn();
5
5
  const bootStoreMock = vi.fn();
6
6
  const checkRegistryVersionMock = vi.fn();
@@ -8,7 +8,7 @@ const collectStoreSummaryMock = vi.fn();
8
8
 
9
9
  vi.mock("#config", async (importOriginal) => ({
10
10
  ...(await importOriginal<typeof import("#config")>()),
11
- readConfig: readConfigMock,
11
+ readConfigLayers: readConfigLayersMock,
12
12
  }));
13
13
 
14
14
  vi.mock("#package-manager", async (importOriginal) => {
@@ -46,12 +46,23 @@ describe("collectInfo", () => {
46
46
  scope: "global",
47
47
  label: "bun (global)",
48
48
  });
49
- readConfigMock.mockReturnValue({ tier: "apps/lxd", channel: "normal" });
49
+ readConfigLayersMock.mockReturnValue({
50
+ config: { tier: "apps/lxd", channel: "normal" },
51
+ origins: {
52
+ tier: "project",
53
+ channel: "default",
54
+ packages: "default",
55
+ trace: "default",
56
+ framework: "default",
57
+ },
58
+ global: { path: "/home/u/.config/pragma/config.json", exists: false },
59
+ project: { path: "/repo/pragma.config.json", exists: true },
60
+ });
50
61
  });
51
62
 
52
63
  it("includes update information and store summary when available", async () => {
53
64
  const dispose = vi.fn();
54
- bootStoreMock.mockResolvedValue({ dispose });
65
+ bootStoreMock.mockResolvedValue({ store: { dispose }, packages: [] });
55
66
  checkRegistryVersionMock.mockResolvedValue({
56
67
  latest: "9.9.9",
57
68
  distTag: "latest",
@@ -91,7 +102,7 @@ describe("collectInfo", () => {
91
102
  it("omits the update section when already on the latest version", async () => {
92
103
  const { VERSION } = await import("#constants");
93
104
  const dispose = vi.fn();
94
- bootStoreMock.mockResolvedValue({ dispose });
105
+ bootStoreMock.mockResolvedValue({ store: { dispose }, packages: [] });
95
106
  checkRegistryVersionMock.mockResolvedValue({
96
107
  latest: VERSION,
97
108
  distTag: "latest",
@@ -1,15 +1,14 @@
1
- import { readConfig } from "#config";
1
+ import { readConfigLayers } from "#config";
2
2
  import { VERSION } from "#constants";
3
3
  import { detectInstallSource, PM_COMMANDS } from "#package-manager";
4
- import {
5
- type PackageRef,
6
- parsePackageEntry,
4
+ import type {
5
+ PackageRef,
6
+ RawPackageEntry,
7
7
  } from "../../refs/operations/parseRef.js";
8
- import readGlobalRefs from "../../refs/operations/readGlobalRefs.js";
9
8
  import { bootStore } from "../../shared/bootStore.js";
10
9
  import { CHANNEL_RELEASES } from "../../shared/filters/buildChannelFilter.js";
11
10
  import { resolveTierChain } from "../../shared/filters/buildTierFilter.js";
12
- import { DEFAULT_PACKAGES } from "../../shared/packages.js";
11
+ import { mergeAndParseRefs } from "../../shared/mergeAndParseRefs.js";
13
12
  import type { InfoData, PackageRefSummary } from "../types.js";
14
13
  import checkRegistryVersion from "./checkRegistryVersion.js";
15
14
  import { collectStoreSummary } from "./collectStoreSummary.js";
@@ -28,7 +27,8 @@ import { collectStoreSummary } from "./collectStoreSummary.js";
28
27
  export default async function collectInfo(cwd: string): Promise<InfoData> {
29
28
  const install = detectInstallSource();
30
29
  const pm = install.packageManager;
31
- const config = readConfig(cwd);
30
+ const layers = readConfigLayers(cwd);
31
+ const config = layers.config;
32
32
  const tierChain = resolveTierChain(config.tier);
33
33
  const channelReleases = CHANNEL_RELEASES[config.channel];
34
34
 
@@ -48,14 +48,14 @@ export default async function collectInfo(cwd: string): Promise<InfoData> {
48
48
  }
49
49
 
50
50
  let store: InfoData["store"];
51
- let keStore: Awaited<ReturnType<typeof bootStore>> | undefined;
51
+ let bootResult: Awaited<ReturnType<typeof bootStore>> | undefined;
52
52
  try {
53
- keStore = await bootStore({ cwd });
54
- store = await collectStoreSummary(keStore);
53
+ bootResult = await bootStore({ cwd });
54
+ store = await collectStoreSummary(bootResult.store);
55
55
  } catch {
56
56
  // Store unavailable — show info without store section
57
57
  } finally {
58
- keStore?.dispose();
58
+ bootResult?.store.dispose();
59
59
  }
60
60
 
61
61
  // Collect package ref summaries
@@ -65,7 +65,9 @@ export default async function collectInfo(cwd: string): Promise<InfoData> {
65
65
  version: VERSION,
66
66
  pm,
67
67
  installSource: install.label,
68
- configPath: "pragma.config.json",
68
+ configPath: layers.project.exists
69
+ ? layers.project.path
70
+ : layers.global.path,
69
71
  tier: config.tier,
70
72
  tierChain,
71
73
  channel: config.channel,
@@ -78,14 +80,9 @@ export default async function collectInfo(cwd: string): Promise<InfoData> {
78
80
  }
79
81
 
80
82
  function collectPackageRefSummaries(
81
- projectPackages?: ReadonlyArray<
82
- string | { readonly name: string; readonly source?: string }
83
- >,
83
+ configPackages?: ReadonlyArray<RawPackageEntry>,
84
84
  ): PackageRefSummary[] {
85
- const entries = projectPackages ?? readGlobalRefs();
86
- const raw = entries.length > 0 ? entries : DEFAULT_PACKAGES.map((pkg) => pkg);
87
-
88
- return raw.map((entry) => refToSummary(parsePackageEntry(entry)));
85
+ return mergeAndParseRefs(configPackages).map(refToSummary);
89
86
  }
90
87
 
91
88
  function refToSummary(ref: PackageRef): PackageRefSummary {
@@ -0,0 +1,91 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { VERSION } from "#constants";
3
+ import { buildCapabilitiesCommand } from "./commands/index.js";
4
+ import { TOOL_CATALOG } from "./data/index.js";
5
+ import { buildCapabilitiesData } from "./mcp/index.js";
6
+
7
+ describe("buildCapabilitiesData", () => {
8
+ it("returns correct version", () => {
9
+ const data = buildCapabilitiesData();
10
+ expect(data.version).toBe(VERSION);
11
+ });
12
+
13
+ it("includes conventions with three fields", () => {
14
+ const data = buildCapabilitiesData();
15
+ expect(data.conventions.system).toBeTruthy();
16
+ expect(data.conventions.model).toBeTruthy();
17
+ expect(data.conventions.querying).toBeTruthy();
18
+ });
19
+
20
+ it("includes a 3-stage discovery sequence", () => {
21
+ const data = buildCapabilitiesData();
22
+ expect(data.discovery_sequence).toHaveLength(3);
23
+ expect(data.discovery_sequence[0]?.stage).toBe(1);
24
+ expect(data.discovery_sequence[0]?.tool).toBe("capabilities");
25
+ expect(data.discovery_sequence[1]?.tool).toBe("*_sample");
26
+ expect(data.discovery_sequence[2]?.tool).toBe("domain tools");
27
+ });
28
+
29
+ it("includes every tool from TOOL_CATALOG", () => {
30
+ const data = buildCapabilitiesData();
31
+ expect(data.tools).toHaveLength(TOOL_CATALOG.length);
32
+ expect(data.tools).toHaveLength(30);
33
+ });
34
+
35
+ it("every tool has a non-empty use_when", () => {
36
+ const data = buildCapabilitiesData();
37
+ for (const tool of data.tools) {
38
+ expect(tool.use_when.length).toBeGreaterThan(0);
39
+ }
40
+ });
41
+
42
+ it("counts match tool catalog category lengths", () => {
43
+ const data = buildCapabilitiesData();
44
+ expect(data.counts.total).toBe(30);
45
+ expect(data.counts.read).toBe(
46
+ TOOL_CATALOG.filter((t) => t.category === "read").length,
47
+ );
48
+ expect(data.counts.write).toBe(
49
+ TOOL_CATALOG.filter((t) => t.category === "write").length,
50
+ );
51
+ expect(data.counts.orientation).toBe(
52
+ TOOL_CATALOG.filter((t) => t.category === "orientation").length,
53
+ );
54
+ expect(data.counts.diagnostic).toBe(
55
+ TOOL_CATALOG.filter((t) => t.category === "diagnostic").length,
56
+ );
57
+ });
58
+
59
+ it("includes limits section", () => {
60
+ const data = buildCapabilitiesData();
61
+ expect(data.limits.output_modes).toContain("text");
62
+ expect(data.limits.output_modes).toContain("json");
63
+ expect(data.limits.output_modes).toContain("llm");
64
+ expect(data.limits.condensed_available).toBe(true);
65
+ });
66
+ });
67
+
68
+ describe("buildCapabilitiesCommand", () => {
69
+ it("returns an output result with plain renderer", async () => {
70
+ const cmd = buildCapabilitiesCommand();
71
+ expect(cmd.path).toEqual(["capabilities"]);
72
+
73
+ const result = await cmd.execute({}, {} as never);
74
+ expect(result.tag).toBe("output");
75
+ if (result.tag !== "output") throw new Error("Expected output result");
76
+
77
+ const text = result.render.plain(result.value) as string;
78
+ expect(text).toContain("Conventions");
79
+ expect(text).toContain("Discovery Sequence");
80
+ expect(text).toContain("block_list");
81
+ expect(text).toContain("read");
82
+ expect(text).toContain("30 tools");
83
+ });
84
+
85
+ it("does not require a store or runtime", async () => {
86
+ const cmd = buildCapabilitiesCommand();
87
+ // Execute with no context — should succeed because it's static
88
+ const result = await cmd.execute({}, {} as never);
89
+ expect(result.tag).toBe("output");
90
+ });
91
+ });
@@ -0,0 +1,28 @@
1
+ import {
2
+ type CommandDefinition,
3
+ type CommandResult,
4
+ createOutputResult,
5
+ } from "@canonical/cli-core";
6
+ import renderCapabilities from "../formatters/capabilities.js";
7
+ import { buildCapabilitiesData } from "../mcp/specs.js";
8
+
9
+ /**
10
+ * Builds the `pragma capabilities` command definition.
11
+ *
12
+ * Returns a static system map: conventions, tool catalog with behavioral
13
+ * hints, discovery sequence, and output modes. No store needed.
14
+ *
15
+ * @returns A command definition for `capabilities`.
16
+ */
17
+ export default function buildCapabilitiesCommand(): CommandDefinition {
18
+ return {
19
+ path: ["capabilities"],
20
+ description:
21
+ "Discover conventions, available tools, and discovery sequence",
22
+ parameters: [],
23
+ execute: async (): Promise<CommandResult> => {
24
+ const data = buildCapabilitiesData();
25
+ return createOutputResult(data, { plain: renderCapabilities });
26
+ },
27
+ };
28
+ }
@@ -1,3 +1,4 @@
1
1
  /** @module Barrel for llm command builders. */
2
2
 
3
+ export { default as buildCapabilitiesCommand } from "./capabilities.js";
3
4
  export { default as buildLlmCommand } from "./llm.js";
@@ -1,25 +1,97 @@
1
1
  import type { CommandRefEntry } from "../types.js";
2
+ import { TOOL_CATALOG } from "./toolCatalog.js";
3
+
4
+ /** Look up a use_when string from the tool catalog by MCP tool name. */
5
+ function hintFor(mcpName: string): string {
6
+ return TOOL_CATALOG.find((t) => t.name === mcpName)?.use_when ?? "";
7
+ }
2
8
 
3
9
  /**
4
- * Static command reference table with approximate token-cost estimates.
10
+ * Static command reference table with approximate token-cost estimates
11
+ * and behavioral hints for LLM tool selection.
5
12
  *
6
- * Used by the `pragma llm` orientation output to help LLMs budget context.
13
+ * Used by the `pragma llm` orientation output to help LLMs budget context
14
+ * and choose the right tool.
7
15
  */
8
16
  export const COMMAND_REFERENCE: readonly CommandRefEntry[] = [
9
- { command: "block list", tokens: "~200" },
10
- { command: "block lookup <name-or-iri...> --detailed", tokens: "~500" },
11
- { command: "standard list --category <cat>", tokens: "~100" },
12
- { command: "standard lookup <name-or-iri...> --detailed", tokens: "~400" },
13
- { command: "standard categories", tokens: "~50" },
14
- { command: "modifier list", tokens: "~100" },
15
- { command: "modifier lookup <name-or-iri...>", tokens: "~80" },
16
- { command: "token list", tokens: "~400" },
17
- { command: "token lookup <name-or-iri...> --detailed", tokens: "~150" },
18
- { command: "tier list", tokens: "~50" },
19
- { command: "ontology list", tokens: "~80" },
20
- { command: "ontology show <prefix>", tokens: "~300" },
21
- { command: 'graph query "<sparql>"', tokens: "varies" },
22
- { command: "graph inspect <uri>", tokens: "~200" },
23
- { command: "config show", tokens: "~50" },
24
- { command: "info", tokens: "~100" },
17
+ {
18
+ command: "block sample",
19
+ tokens: "~600",
20
+ use_when: hintFor("block_sample"),
21
+ },
22
+ { command: "block list", tokens: "~200", use_when: hintFor("block_list") },
23
+ {
24
+ command: "block lookup <name-or-iri...> --detailed",
25
+ tokens: "~500",
26
+ use_when: hintFor("block_lookup"),
27
+ },
28
+ {
29
+ command: "standard sample",
30
+ tokens: "~500",
31
+ use_when: hintFor("standard_sample"),
32
+ },
33
+ {
34
+ command: "standard list --category <cat>",
35
+ tokens: "~100",
36
+ use_when: hintFor("standard_list"),
37
+ },
38
+ {
39
+ command: "standard lookup <name-or-iri...> --detailed",
40
+ tokens: "~400",
41
+ use_when: hintFor("standard_lookup"),
42
+ },
43
+ {
44
+ command: "standard categories",
45
+ tokens: "~50",
46
+ use_when: hintFor("standard_categories"),
47
+ },
48
+ {
49
+ command: "modifier sample",
50
+ tokens: "~200",
51
+ use_when: hintFor("modifier_sample"),
52
+ },
53
+ {
54
+ command: "modifier list",
55
+ tokens: "~100",
56
+ use_when: hintFor("modifier_list"),
57
+ },
58
+ {
59
+ command: "modifier lookup <name-or-iri...>",
60
+ tokens: "~80",
61
+ use_when: hintFor("modifier_lookup"),
62
+ },
63
+ {
64
+ command: "token sample",
65
+ tokens: "~300",
66
+ use_when: hintFor("token_sample"),
67
+ },
68
+ { command: "token list", tokens: "~400", use_when: hintFor("token_list") },
69
+ {
70
+ command: "token lookup <name-or-iri...> --detailed",
71
+ tokens: "~150",
72
+ use_when: hintFor("token_lookup"),
73
+ },
74
+ { command: "tier list", tokens: "~50", use_when: hintFor("tier_list") },
75
+ {
76
+ command: "ontology list",
77
+ tokens: "~80",
78
+ use_when: hintFor("ontology_list"),
79
+ },
80
+ {
81
+ command: "ontology show <prefix>",
82
+ tokens: "~300",
83
+ use_when: hintFor("ontology_show"),
84
+ },
85
+ {
86
+ command: 'graph query "<sparql>"',
87
+ tokens: "varies",
88
+ use_when: hintFor("graph_query"),
89
+ },
90
+ {
91
+ command: "graph inspect <uri>",
92
+ tokens: "~200",
93
+ use_when: hintFor("graph_inspect"),
94
+ },
95
+ { command: "config show", tokens: "~50", use_when: hintFor("config_show") },
96
+ { command: "info", tokens: "~100", use_when: hintFor("info") },
25
97
  ];
@@ -9,21 +9,22 @@ import type { DecisionTree } from "../types.js";
9
9
  export const DECISION_TREES: readonly DecisionTree[] = [
10
10
  {
11
11
  intent: "Build a block",
12
- tree: `? Know IRI or name?
13
- yes → block lookup <name-or-iri...> --detailed [~500]
14
- e.g. block lookup ds:global.component.button
15
- no → block list [~200] → pick compact IRI → lookup`,
12
+ tree: `? First time seeing block data?
13
+ yes → block sample [~600] → see actual shapes, then query
14
+ no → ? Know IRI or name?
15
+ yes → block lookup <name-or-iri...> --detailed [~500]
16
+ e.g. block lookup ds:global.component.button
17
+ no → block list [~200] → pick compact IRI → lookup`,
16
18
  },
17
19
  {
18
20
  intent: "Audit standards",
19
- tree: `? Know standard IRI or name?
20
- yes → standard lookup <name-or-iri...> --detailed [~400]
21
- e.g. standard lookup react/component/props
22
- no → ? Know block IRI or name?
23
- yes → block lookup <name-or-iri...> --detailed [~500]
24
- → inspect related guidance manually Σ500
25
- no → standard list --category <cat> [~100]
26
- → standard lookup <std-iri...> --detailed [~400] Σ500`,
21
+ tree: `? First time seeing standard data?
22
+ yes → standard sample [~500] → see actual shapes, then query
23
+ no → ? Know standard IRI or name?
24
+ yes → standard lookup <name-or-iri...> --detailed [~400]
25
+ e.g. standard lookup react/component/props
26
+ no → standard list --category <cat> [~100]
27
+ → standard lookup <std-iri...> --detailed [~400] Σ500`,
27
28
  },
28
29
  {
29
30
  intent: "Find a token",
@@ -34,7 +35,8 @@ export const DECISION_TREES: readonly DecisionTree[] = [
34
35
  },
35
36
  {
36
37
  intent: "Explore the design system",
37
- tree: `high-level → ontology list [~80] → ontology show <ns> [~300]
38
+ tree: `first time → block sample / token sample / modifier sample [~300] → see real shapes
39
+ high-level → ontology list [~80] → ontology show <ns> [~300]
38
40
  modifiers → modifier list [~100] → modifier lookup <name-or-iri...> [~80]
39
41
  tiers → tier list [~50]
40
42
  raw → graph query "SELECT ..." → graph inspect <uri> [~200]`,
@@ -2,3 +2,5 @@
2
2
 
3
3
  export { COMMAND_REFERENCE } from "./commandReference.js";
4
4
  export { DECISION_TREES } from "./decisionTrees.js";
5
+ export type { ToolEntry } from "./toolCatalog.js";
6
+ export { TOOL_CATALOG } from "./toolCatalog.js";
@@ -0,0 +1,190 @@
1
+ /** Tool catalog with behavioral hints for agent orientation. */
2
+
3
+ export interface ToolEntry {
4
+ readonly name: string;
5
+ readonly category: "read" | "write" | "orientation" | "diagnostic";
6
+ readonly use_when: string;
7
+ }
8
+
9
+ /** All registered MCP tools with category and behavioral guidance. */
10
+ export const TOOL_CATALOG: readonly ToolEntry[] = [
11
+ // — Read ————————————————————————————————————————————————————————————————————
12
+ {
13
+ name: "block_list",
14
+ category: "read",
15
+ use_when:
16
+ "Browsing available components, patterns, layouts under current tier/channel",
17
+ },
18
+ {
19
+ name: "block_lookup",
20
+ category: "read",
21
+ use_when:
22
+ "Need full anatomy, modifiers, tokens, and standards for specific blocks by name or IRI",
23
+ },
24
+ {
25
+ name: "standard_list",
26
+ category: "read",
27
+ use_when:
28
+ "Browsing code standards, optionally filtered by category or search term",
29
+ },
30
+ {
31
+ name: "standard_lookup",
32
+ category: "read",
33
+ use_when:
34
+ "Need do/don't code examples for specific coding standards by name or IRI",
35
+ },
36
+ {
37
+ name: "standard_categories",
38
+ category: "read",
39
+ use_when: "Discovering which standard categories exist before filtering",
40
+ },
41
+ {
42
+ name: "modifier_list",
43
+ category: "read",
44
+ use_when: "Listing all modifier families and their allowed values",
45
+ },
46
+ {
47
+ name: "modifier_lookup",
48
+ category: "read",
49
+ use_when:
50
+ "Need values and usage details for specific modifier families by name",
51
+ },
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
+ },
64
+ {
65
+ name: "tier_list",
66
+ category: "read",
67
+ use_when: "Understanding the tier hierarchy before setting a tier filter",
68
+ },
69
+ {
70
+ name: "config_show",
71
+ category: "read",
72
+ use_when: "Checking active tier and channel before querying",
73
+ },
74
+ {
75
+ name: "ontology_list",
76
+ category: "read",
77
+ use_when:
78
+ "Discovering loaded namespaces, prefixes, and class/property counts",
79
+ },
80
+ {
81
+ name: "ontology_show",
82
+ category: "read",
83
+ use_when:
84
+ "Exploring the full schema of a namespace — classes, properties, and hierarchy",
85
+ },
86
+ {
87
+ name: "graph_query",
88
+ category: "read",
89
+ use_when:
90
+ "Complex SPARQL joins or aggregations that other tools cannot express",
91
+ },
92
+ {
93
+ name: "graph_inspect",
94
+ category: "read",
95
+ use_when:
96
+ "Examining all triples for a specific URI — predicates, objects, and types",
97
+ },
98
+ {
99
+ name: "skill_list",
100
+ category: "read",
101
+ use_when: "Discovering agent skills provided by installed packages",
102
+ },
103
+ {
104
+ name: "skill_lookup",
105
+ category: "read",
106
+ use_when:
107
+ "Loading full SKILL.md instructions for a specific agent skill by name",
108
+ },
109
+ {
110
+ name: "block_sample",
111
+ category: "read",
112
+ use_when:
113
+ "See actual block data shapes before querying — returns random instances each call, prevents guessing at property names",
114
+ },
115
+ {
116
+ name: "standard_sample",
117
+ category: "read",
118
+ use_when:
119
+ "See actual standard data shapes (with dos/donts) before querying — returns random instances each call",
120
+ },
121
+ {
122
+ name: "token_sample",
123
+ category: "read",
124
+ use_when:
125
+ "See actual token data shapes (with theme values) before querying — returns random instances each call",
126
+ },
127
+ {
128
+ name: "modifier_sample",
129
+ category: "read",
130
+ use_when:
131
+ "See actual modifier data shapes (with value lists) before querying — returns random instances each call",
132
+ },
133
+
134
+ // — Write ———————————————————————————————————————————————————————————————————
135
+ {
136
+ name: "config_tier",
137
+ category: "write",
138
+ use_when: "Setting or resetting the active tier filter",
139
+ },
140
+ {
141
+ name: "config_channel",
142
+ category: "write",
143
+ use_when:
144
+ "Setting the release channel (normal, experimental, or prerelease)",
145
+ },
146
+ {
147
+ name: "tokens_add_config",
148
+ category: "write",
149
+ use_when: "Generating a tokens.config.mjs for the terrazzo token pipeline",
150
+ },
151
+ {
152
+ name: "create_component",
153
+ category: "write",
154
+ use_when:
155
+ "Scaffolding a new design system component (React, Svelte, or Lit)",
156
+ },
157
+ {
158
+ name: "create_package",
159
+ category: "write",
160
+ use_when:
161
+ "Scaffolding a new npm package with proper monorepo configuration",
162
+ },
163
+
164
+ // — Orientation —————————————————————————————————————————————————————————————
165
+ {
166
+ name: "llm",
167
+ category: "orientation",
168
+ use_when:
169
+ "Need live context, decision trees, and command reference for design system work",
170
+ },
171
+ {
172
+ name: "capabilities",
173
+ category: "orientation",
174
+ use_when:
175
+ "Starting a session — understand conventions, available tools, and discovery flow",
176
+ },
177
+
178
+ // — Diagnostic ——————————————————————————————————————————————————————————————
179
+ {
180
+ name: "doctor",
181
+ category: "diagnostic",
182
+ use_when:
183
+ "Diagnosing environment issues — config, store, completions, MCP health",
184
+ },
185
+ {
186
+ name: "info",
187
+ category: "diagnostic",
188
+ use_when: "Checking pragma version, configuration summary, and store state",
189
+ },
190
+ ];
@@ -0,0 +1,50 @@
1
+ import type { CapabilitiesData } from "../types.js";
2
+
3
+ /**
4
+ * Render capabilities data as compact terminal text.
5
+ *
6
+ * @param data - The structured capabilities payload.
7
+ * @returns Plain text for terminal output.
8
+ */
9
+ export default function renderCapabilities(data: CapabilitiesData): string {
10
+ const lines: string[] = [];
11
+
12
+ lines.push(`pragma v${data.version}`);
13
+ lines.push("");
14
+
15
+ // — Conventions
16
+ lines.push("Conventions");
17
+ lines.push(` ${data.conventions.system}`);
18
+ lines.push(` ${data.conventions.model}`);
19
+ lines.push(` ${data.conventions.querying}`);
20
+ lines.push("");
21
+
22
+ // — Discovery sequence
23
+ lines.push("Discovery Sequence");
24
+ for (const stage of data.discovery_sequence) {
25
+ lines.push(` ${stage.stage}. ${stage.tool} — ${stage.purpose}`);
26
+ }
27
+ lines.push("");
28
+
29
+ // — Tools by category
30
+ const categories = ["read", "write", "orientation", "diagnostic"] as const;
31
+ for (const cat of categories) {
32
+ const tools = data.tools.filter((t) => t.category === cat);
33
+ lines.push(`${cat} (${tools.length})`);
34
+ for (const tool of tools) {
35
+ lines.push(` ${tool.name} — ${tool.use_when}`);
36
+ }
37
+ lines.push("");
38
+ }
39
+
40
+ // — Counts + limits
41
+ const { counts } = data;
42
+ lines.push(
43
+ `${counts.total} tools: ${counts.read} read, ${counts.write} write, ${counts.orientation} orientation, ${counts.diagnostic} diagnostic`,
44
+ );
45
+ lines.push(
46
+ `output: ${data.limits.output_modes.join(", ")} | condensed: ${data.limits.condensed_available ? "yes" : "no"}`,
47
+ );
48
+
49
+ return lines.join("\n");
50
+ }
@@ -1,3 +1,4 @@
1
1
  /** @module Barrel for llm formatters. */
2
2
 
3
+ export { default as renderCapabilities } from "./capabilities.js";
3
4
  export { default as renderLlmOrientation } from "./orientation.js";