@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
@@ -0,0 +1,26 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import modifierEmptyError from "./modifierEmptyError.js";
3
+
4
+ describe("modifierEmptyError", () => {
5
+ it("recovers via a runnable install command (store-empty is its only scenario)", () => {
6
+ const err = modifierEmptyError();
7
+
8
+ // `modifier list` takes no filters, so an empty result is always
9
+ // store-empty: the recovery is the install, not a widen.
10
+ expect(err.recovery).toEqual({
11
+ message: "Install the design system packages that provide modifiers.",
12
+ cli: "bun add -D @canonical/design-system",
13
+ });
14
+ });
15
+
16
+ it("cites a real default package, not @canonical/ds-global", () => {
17
+ const err = modifierEmptyError();
18
+ expect(err.recovery?.cli).toContain("@canonical/design-system");
19
+ expect(err.recovery?.cli).not.toContain("ds-global");
20
+ });
21
+
22
+ it("has no mcp retry for store-empty (re-listing would return empty again)", () => {
23
+ const err = modifierEmptyError();
24
+ expect(err.recovery?.mcp).toBeUndefined();
25
+ });
26
+ });
@@ -1,10 +1,15 @@
1
1
  import { PragmaError } from "#error";
2
2
 
3
3
  export default function modifierEmptyError(): PragmaError {
4
+ // `modifier list` takes no filters, so an empty result always means the
5
+ // design system packages that supply modifier triples are absent. The
6
+ // recovery is the runnable install command, not a (non-existent) widen.
4
7
  return PragmaError.emptyResults("modifier", {
5
8
  recovery: {
6
- message:
7
- "Ensure design system packages are installed: bun add -D @canonical/ds-global",
9
+ // The base error already states "No modifiers found"; the recovery adds
10
+ // only the cause + the runnable fix (the cli line is what renders on CLI).
11
+ message: "Install the design system packages that provide modifiers.",
12
+ cli: "bun add -D @canonical/design-system",
8
13
  },
9
14
  });
10
15
  }
@@ -1,6 +1,7 @@
1
1
  import type { LookupContract, LookupResult } from "../../shared/contracts.js";
2
2
  import lookupMany from "../../shared/lookupMany.js";
3
3
  import type { PragmaRuntime } from "../../shared/runtime.js";
4
+ import { expandLookupQueries } from "../../shared/suggestions/index.js";
4
5
  import type { ModifierFamily } from "../../shared/types/index.js";
5
6
  import { lookupModifier } from "../operations/index.js";
6
7
 
@@ -8,11 +9,23 @@ export default async function resolveModifierLookup(
8
9
  store: Pick<PragmaRuntime, "store">["store"],
9
10
  queries: readonly string[],
10
11
  ): Promise<LookupContract<ModifierFamily>> {
11
- const result: LookupResult<ModifierFamily> = await lookupMany(
12
+ const { names, globErrors } = await expandLookupQueries(
12
13
  queries,
13
- (query) => lookupModifier(store, query),
14
+ store,
15
+ "modifier",
14
16
  );
15
17
 
18
+ const lookupResult: LookupResult<ModifierFamily> =
19
+ names.length > 0
20
+ ? await lookupMany(names, (query) => lookupModifier(store, query))
21
+ : { results: [], errors: [], meta: { internalErrorCount: 0 } };
22
+
23
+ const result: LookupResult<ModifierFamily> = {
24
+ results: lookupResult.results,
25
+ errors: [...lookupResult.errors, ...globErrors],
26
+ meta: lookupResult.meta ?? { internalErrorCount: 0 },
27
+ };
28
+
16
29
  return {
17
30
  params: { names: queries },
18
31
  result,
@@ -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
+ });
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Modifier read stories — the single declaration of `modifier list` and
3
+ * `modifier lookup` for both surfaces.
4
+ *
5
+ * The story kernel compiles these into the CLI commands and MCP tools,
6
+ * so descriptions, parameters, resolution, and rendering live here once.
7
+ */
8
+
9
+ import { createListView, createLookupView } from "#tui";
10
+ import type { LookupStory, ReadStory } from "../shared/stories/index.js";
11
+ import type { ModifierFamily } from "../shared/types/index.js";
12
+ import {
13
+ createInkLookupOptions,
14
+ listFormatters,
15
+ lookupFormatters,
16
+ } from "./formatters/index.js";
17
+ import { modifierConfig } from "./modifierConfig.js";
18
+ import {
19
+ resolveModifierList,
20
+ resolveModifierLookup,
21
+ } from "./orchestration/index.js";
22
+ import type { ModifierListResolution } from "./types.js";
23
+
24
+ /** The `modifier list` / `modifier_list` read story. */
25
+ export const modifierListStory: ReadStory<
26
+ ModifierListResolution,
27
+ ModifierFamily[]
28
+ > = {
29
+ noun: "modifier",
30
+ verb: "list",
31
+ description: "List all modifier families",
32
+ toolDescription: "List all modifier families with their values.",
33
+ params: [],
34
+ examples: ["pragma modifier list", "pragma modifier list --llm"],
35
+ resolve: (rt) => resolveModifierList(rt),
36
+ toOutput: (resolution) => [...resolution.items],
37
+ formatters: listFormatters,
38
+ toEnvelope: (resolution) => ({
39
+ data: resolution.items,
40
+ meta: { count: resolution.items.length },
41
+ }),
42
+ renderInk: (items) =>
43
+ createListView({
44
+ heading: "Modifiers",
45
+ domain: "modifier",
46
+ items,
47
+ columns: modifierConfig.listColumns,
48
+ }),
49
+ };
50
+
51
+ /** The `modifier lookup` / `modifier_lookup` read story. */
52
+ export const modifierLookupStory: LookupStory<ModifierFamily, ModifierFamily> =
53
+ {
54
+ noun: "modifier",
55
+ description: "Look up a modifier family and its values",
56
+ toolDescription: "Get one or more modifier families and their values.",
57
+ namesDescription: "Modifier family names or IRIs",
58
+ namesToolDescription: "Modifier family names or IRIs to look up",
59
+ examples: [
60
+ "pragma modifier lookup importance",
61
+ "pragma modifier lookup importance density",
62
+ "pragma modifier lookup importance --llm",
63
+ ],
64
+ resolve: async (rt, names) => {
65
+ const contract = await resolveModifierLookup(rt.store, names);
66
+ return contract.result;
67
+ },
68
+ toFmtInput: (family) => family,
69
+ formatters: lookupFormatters,
70
+ renderInk: (result) =>
71
+ createLookupView({
72
+ results: result.results,
73
+ errors: result.errors,
74
+ domain: "modifier",
75
+ options: createInkLookupOptions(),
76
+ }),
77
+ };
@@ -1,64 +1,11 @@
1
- import {
2
- type CommandDefinition,
3
- type CommandResult,
4
- createOutputResult,
5
- } from "@canonical/cli-core";
6
- import { PragmaError } from "#error";
7
- import { createListView } from "#tui";
1
+ import type { CommandDefinition } from "@canonical/cli-core";
8
2
  import type { PragmaContext } from "../../shared/context.js";
9
- import type { ColumnDef } from "../../shared/contracts.js";
10
- import { selectFormatter } from "../../shared/formatters.js";
11
- import type { OntologySummary } from "../../shared/types/ontology.js";
12
- import { listFormatters } from "../formatters/index.js";
13
- import { listOntologies } from "../operations/index.js";
3
+ import { compileReadCommand } from "../../shared/stories/index.js";
4
+ import { ontologyListStory } from "../stories.js";
14
5
 
15
- const ontologyListColumns: readonly ColumnDef<OntologySummary>[] = [
16
- { key: "prefix", label: "Prefix" },
17
- { key: "namespace", label: "Namespace" },
18
- { key: "classCount", label: "Classes" },
19
- { key: "propertyCount", label: "Properties" },
20
- { key: "anatomyCount", label: "Anatomies" },
21
- ];
22
-
23
- /**
24
- * Builds the `pragma ontology list` command definition.
25
- *
26
- * Lists all loaded ontology namespaces with class and property counts.
27
- *
28
- * @param ctx - Pragma runtime context providing the ke store and config.
29
- * @returns A command definition for `ontology list`.
30
- */
6
+ /** Wire the `pragma ontology list` CLI command from the ontology list story. */
31
7
  export default function buildListCommand(
32
8
  ctx: PragmaContext,
33
9
  ): CommandDefinition {
34
- return {
35
- path: ["ontology", "list"],
36
- description: "List loaded ontologies",
37
- parameters: [],
38
- meta: {
39
- examples: ["pragma ontology list", "pragma ontology list --llm"],
40
- },
41
- execute: async (): Promise<CommandResult> => {
42
- const ontologies = await listOntologies(ctx.store);
43
-
44
- if (ontologies.length === 0) {
45
- throw PragmaError.emptyResults("ontology", {
46
- recovery: {
47
- message: "Ensure design system packages are installed.",
48
- },
49
- });
50
- }
51
-
52
- return createOutputResult(ontologies, {
53
- plain: selectFormatter(ctx, listFormatters),
54
- ink: (data) =>
55
- createListView({
56
- heading: "Ontologies",
57
- domain: "ontology",
58
- items: data,
59
- columns: ontologyListColumns,
60
- }),
61
- });
62
- },
63
- };
10
+ return compileReadCommand(ctx, ontologyListStory);
64
11
  }
@@ -1,66 +1,14 @@
1
- import {
2
- type CommandDefinition,
3
- type CommandResult,
4
- createOutputResult,
5
- } from "@canonical/cli-core";
6
- import { PragmaError } from "#error";
1
+ import type { CommandDefinition } from "@canonical/cli-core";
7
2
  import type { PragmaContext } from "../../shared/context.js";
8
- import { selectFormatter } from "../../shared/formatters.js";
9
- import { showFormatters } from "../formatters/index.js";
10
- import { listOntologies, showOntology } from "../operations/index.js";
3
+ import { compileReadCommand } from "../../shared/stories/index.js";
4
+ import { ontologyShowStory } from "../stories.js";
11
5
 
12
6
  /**
13
- * Builds the `pragma ontology show` command definition.
14
- *
15
- * Displays detailed schema (classes and properties) for a given ontology
16
- * prefix. Provides tab-completion for the prefix parameter.
17
- *
18
- * @param ctx - Pragma runtime context providing the ke store and config.
19
- * @returns A command definition for `ontology show`.
7
+ * Wire the `pragma ontology show <prefix>` CLI command from the ontology
8
+ * show story.
20
9
  */
21
10
  export default function buildShowCommand(
22
11
  ctx: PragmaContext,
23
12
  ): CommandDefinition {
24
- return {
25
- path: ["ontology", "show"],
26
- description: "Show ontology schema details",
27
- parameters: [
28
- {
29
- name: "prefix",
30
- description: "Ontology prefix (e.g. 'ds', 'cs')",
31
- type: "string",
32
- positional: true,
33
- required: true,
34
- complete: async (partial: string) => {
35
- const all = await listOntologies(ctx.store);
36
- return all
37
- .map((o) => o.prefix)
38
- .filter((p) => p.toLowerCase().startsWith(partial.toLowerCase()));
39
- },
40
- },
41
- ],
42
- meta: {
43
- examples: ["pragma ontology show ds", "pragma ontology show cs --llm"],
44
- },
45
- execute: async (
46
- params: Record<string, unknown>,
47
- ): Promise<CommandResult> => {
48
- const prefix = params.prefix as string;
49
- if (!prefix) {
50
- throw PragmaError.invalidInput("prefix", "(empty)", {
51
- recovery: {
52
- message: "List loaded ontologies to find valid prefixes.",
53
- cli: "pragma ontology list",
54
- mcp: { tool: "ontology_list" },
55
- },
56
- });
57
- }
58
-
59
- const result = await showOntology(ctx.store, prefix);
60
-
61
- return createOutputResult(result, {
62
- plain: selectFormatter(ctx, showFormatters),
63
- });
64
- },
65
- };
13
+ return compileReadCommand(ctx, ontologyShowStory);
66
14
  }
@@ -1,5 +1,11 @@
1
1
  import chalk from "chalk";
2
- import { formatHeading, formatSection } from "#pipeline";
2
+ // Deep import, not #pipeline: the barrel re-exports collectCommands, which
3
+ // imports every domain barrel — including this one — so #pipeline here forms
4
+ // a module cycle that evaluates this domain's stories as undefined at load.
5
+ import {
6
+ formatHeading,
7
+ formatSection,
8
+ } from "../../../pipeline/formatTerminal.js";
3
9
  import compactUri from "../../shared/compactUri.js";
4
10
  import type { Formatters } from "../../shared/formatters.js";
5
11
  import { PREFIX_MAP } from "../../shared/prefixes.js";
@@ -1,93 +1,16 @@
1
1
  /**
2
- * MCP tool specs for the ontology domain.
2
+ * MCP tool specs for the ontology domain — ontology_list and
3
+ * ontology_show, compiled from the ontology read stories in
4
+ * `../stories.ts` so both surfaces share formatters and resolution.
3
5
  */
4
6
 
7
+ import { compileReadTool } from "../../shared/stories/index.js";
5
8
  import type { ToolSpec } from "../../shared/ToolSpec.js";
6
- import { listOntologies, showOntology } from "../operations/index.js";
9
+ import { ontologyListStory, ontologyShowStory } from "../stories.js";
7
10
 
8
11
  const specs: readonly ToolSpec[] = [
9
- {
10
- name: "ontology_list",
11
- description:
12
- "List all ontologies loaded in the knowledge graph with class and property counts.",
13
- params: {
14
- condensed: {
15
- type: "boolean",
16
- description: "Token-optimized output",
17
- optional: true,
18
- },
19
- },
20
- readOnly: true,
21
- async execute(rt, { condensed }) {
22
- const result = await listOntologies(rt.store);
23
-
24
- if (condensed) {
25
- const lines = ["## Ontologies", ""];
26
- for (const o of result) {
27
- lines.push(
28
- `- **${o.prefix}:** (${o.namespace}) | classes: ${o.classCount} | properties: ${o.propertyCount}`,
29
- );
30
- }
31
- const text = lines.join("\n");
32
- return {
33
- condensed: true,
34
- text,
35
- tokens: `~${Math.ceil(text.length / 4)}`,
36
- };
37
- }
38
-
39
- return { data: result, meta: { count: result.length } };
40
- },
41
- },
42
- {
43
- name: "ontology_show",
44
- description:
45
- "Show detailed schema for an ontology including classes and properties.",
46
- params: {
47
- prefix: {
48
- type: "string",
49
- description: "Ontology prefix (e.g. 'ds', 'cs')",
50
- optional: false,
51
- },
52
- condensed: {
53
- type: "boolean",
54
- description: "Token-optimized output",
55
- optional: true,
56
- },
57
- },
58
- readOnly: true,
59
- async execute(rt, { prefix, condensed }) {
60
- const result = await showOntology(rt.store, prefix as string);
61
-
62
- if (condensed) {
63
- const lines = [`## ${result.prefix}: (${result.namespace})`, ""];
64
- if (result.classes.length > 0) {
65
- lines.push("### Classes");
66
- for (const c of result.classes) {
67
- const sup = c.superclass ? ` extends ${c.superclass}` : "";
68
- lines.push(`- **${c.label}**${sup}`);
69
- }
70
- lines.push("");
71
- }
72
- if (result.properties.length > 0) {
73
- lines.push("### Properties");
74
- for (const p of result.properties) {
75
- const domain = p.domain ? ` domain: ${p.domain}` : "";
76
- const range = p.range ? ` range: ${p.range}` : "";
77
- lines.push(`- **${p.label}** (${p.type})${domain}${range}`);
78
- }
79
- }
80
- const text = lines.join("\n");
81
- return {
82
- condensed: true,
83
- text,
84
- tokens: `~${Math.ceil(text.length / 4)}`,
85
- };
86
- }
87
-
88
- return { data: result };
89
- },
90
- },
12
+ compileReadTool(ontologyListStory),
13
+ compileReadTool(ontologyShowStory),
91
14
  ];
92
15
 
93
16
  export default specs;
@@ -0,0 +1,36 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ontologyListStory, ontologyShowStory } from "./stories.js";
3
+
4
+ describe("ontologyListStory", () => {
5
+ it("renders the ink list view", () => {
6
+ const view = ontologyListStory.renderInk?.([]);
7
+ expect(typeof view).toBe("string");
8
+ expect(view).toContain("Ontologies");
9
+ });
10
+
11
+ it("rejects only empty results", () => {
12
+ expect(ontologyListStory.emptyError?.([], {})).toBeDefined();
13
+ expect(
14
+ ontologyListStory.emptyError?.(
15
+ [
16
+ {
17
+ prefix: "ds",
18
+ namespace: "https://ds.example/",
19
+ classCount: 1,
20
+ propertyCount: 1,
21
+ anatomyCount: 0,
22
+ },
23
+ ],
24
+ {},
25
+ ),
26
+ ).toBeUndefined();
27
+ });
28
+ });
29
+
30
+ describe("ontologyShowStory", () => {
31
+ it("guards against a missing prefix", () => {
32
+ expect(ontologyShowStory.guardParams?.({})).toBeDefined();
33
+ expect(ontologyShowStory.guardParams?.({ prefix: "" })).toBeDefined();
34
+ expect(ontologyShowStory.guardParams?.({ prefix: "ds" })).toBeUndefined();
35
+ });
36
+ });
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Ontology read stories — the single declaration of `ontology list` and
3
+ * `ontology show` for both surfaces.
4
+ *
5
+ * The story kernel compiles these into the CLI commands and MCP tools.
6
+ * Both surfaces now render through the same formatters, so MCP condensed
7
+ * output matches CLI `--llm` output by construction (previously the MCP
8
+ * specs re-implemented the Markdown inline and had drifted).
9
+ */
10
+
11
+ import { PragmaError } from "#error";
12
+ import { createListView } from "#tui";
13
+ import type { ColumnDef } from "../shared/contracts.js";
14
+ import {
15
+ type ReadStory,
16
+ requirePragmaContext,
17
+ } from "../shared/stories/index.js";
18
+ import type {
19
+ OntologyDetailed,
20
+ OntologySummary,
21
+ } from "../shared/types/index.js";
22
+ import { listFormatters, showFormatters } from "./formatters/index.js";
23
+ import { listOntologies, showOntology } from "./operations/index.js";
24
+
25
+ const ontologyListColumns: readonly ColumnDef<OntologySummary>[] = [
26
+ { key: "prefix", label: "Prefix" },
27
+ { key: "namespace", label: "Namespace" },
28
+ { key: "classCount", label: "Classes" },
29
+ { key: "propertyCount", label: "Properties" },
30
+ { key: "anatomyCount", label: "Anatomies" },
31
+ ];
32
+
33
+ /** The `ontology list` / `ontology_list` read story. */
34
+ export const ontologyListStory: ReadStory<
35
+ OntologySummary[],
36
+ readonly OntologySummary[]
37
+ > = {
38
+ noun: "ontology",
39
+ verb: "list",
40
+ description: "List loaded ontologies",
41
+ toolDescription:
42
+ "List all ontologies loaded in the knowledge graph with class and property counts.",
43
+ params: [],
44
+ examples: ["pragma ontology list", "pragma ontology list --llm"],
45
+ resolve: (rt) => listOntologies(rt.store),
46
+ toOutput: (ontologies) => ontologies,
47
+ formatters: listFormatters,
48
+ toEnvelope: (ontologies) => ({
49
+ data: ontologies,
50
+ meta: { count: ontologies.length },
51
+ }),
52
+ emptyError: (ontologies) =>
53
+ ontologies.length === 0
54
+ ? PragmaError.emptyResults("ontology", {
55
+ recovery: {
56
+ message: "Ensure design system packages are installed.",
57
+ },
58
+ })
59
+ : undefined,
60
+ renderInk: (ontologies) =>
61
+ createListView({
62
+ heading: "Ontologies",
63
+ domain: "ontology",
64
+ items: ontologies,
65
+ columns: ontologyListColumns,
66
+ }),
67
+ };
68
+
69
+ /** The `ontology show <prefix>` / `ontology_show` read story. */
70
+ export const ontologyShowStory: ReadStory<OntologyDetailed, OntologyDetailed> =
71
+ {
72
+ noun: "ontology",
73
+ verb: "show",
74
+ description: "Show ontology schema details",
75
+ toolDescription:
76
+ "Show detailed schema for an ontology including classes and properties.",
77
+ params: [
78
+ {
79
+ name: "prefix",
80
+ type: "string",
81
+ description: "Ontology prefix (e.g. 'ds', 'cs')",
82
+ positional: true,
83
+ required: true,
84
+ complete: async (partial, cmdCtx) => {
85
+ const ctx = requirePragmaContext(cmdCtx);
86
+ const all = await listOntologies(ctx.store);
87
+ return all
88
+ .map((o) => o.prefix)
89
+ .filter((p) => p.toLowerCase().startsWith(partial.toLowerCase()));
90
+ },
91
+ },
92
+ ],
93
+ examples: ["pragma ontology show ds", "pragma ontology show cs --llm"],
94
+ resolve: (rt, params) => showOntology(rt.store, params.prefix as string),
95
+ toOutput: (ontology) => ontology,
96
+ formatters: showFormatters,
97
+ toEnvelope: (ontology) => ({ data: ontology }),
98
+ guardParams: (params) =>
99
+ typeof params.prefix === "string" && params.prefix.length > 0
100
+ ? undefined
101
+ : PragmaError.invalidInput("prefix", "(empty)", {
102
+ recovery: {
103
+ message: "List loaded ontologies to find valid prefixes.",
104
+ cli: "pragma ontology list",
105
+ mcp: { tool: "ontology_list" },
106
+ },
107
+ }),
108
+ };
@@ -3,7 +3,7 @@
3
3
  export { cloneRef, fetchRef, isSha, pruneCache } from "./gitOps.js";
4
4
  export type { PackageRef, RawPackageEntry } from "./parseRef.js";
5
5
  export { parsePackageEntry } from "./parseRef.js";
6
- export { cacheRoot, gitCacheDir, globalConfigDir } from "./paths.js";
6
+ export { cacheRoot, dataRoot, gitCacheDir, globalConfigDir } from "./paths.js";
7
7
  export { default as readGlobalRefs } from "./readGlobalRefs.js";
8
8
 
9
9
  export type { UpdateRefsOptions, UpdateResult } from "./updateRefs.js";
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Cross-platform path resolution for pragma cache and global config.
2
+ * Cross-platform path resolution for pragma cache, config, and data.
3
3
  *
4
4
  * Respects XDG Base Directory Specification:
5
5
  * - XDG_CACHE_HOME for cache (default: ~/.cache)
6
6
  * - XDG_CONFIG_HOME for global config (default: ~/.config)
7
+ * - XDG_DATA_HOME for persistent data (default: ~/.local/share)
7
8
  *
8
9
  * Override via PRAGMA_CACHE_DIR for CI and testing.
9
10
  * Uses os.homedir() for macOS/WSL/Linux portability.
@@ -42,6 +43,19 @@ export function globalConfigDir(): string {
42
43
  return join(base, "pragma");
43
44
  }
44
45
 
46
+ /**
47
+ * Root directory for pragma persistent data (extracted skills, etc.).
48
+ *
49
+ * Resolution order:
50
+ * 1. XDG_DATA_HOME/pragma (XDG spec)
51
+ * 2. ~/.local/share/pragma (default)
52
+ */
53
+ export function dataRoot(): string {
54
+ const xdg = process.env.XDG_DATA_HOME;
55
+ const base = xdg ?? join(homedir(), ".local", "share");
56
+ return join(base, "pragma");
57
+ }
58
+
45
59
  /**
46
60
  * Cache directory for a specific git-ref-resolved package.
47
61
  *
@@ -54,6 +68,20 @@ export function gitCacheDir(pkg: string, ref: string): string {
54
68
  return join(cacheRoot(), "refs", pkg, sanitizedRef);
55
69
  }
56
70
 
71
+ /**
72
+ * Root directory for query trace logs.
73
+ *
74
+ * Resolution order:
75
+ * 1. PRAGMA_TRACE_DIR environment variable (CI/testing override)
76
+ * 2. XDG_DATA_HOME/pragma/traces (default)
77
+ */
78
+ export function traceDir(): string {
79
+ if (process.env.PRAGMA_TRACE_DIR) {
80
+ return process.env.PRAGMA_TRACE_DIR;
81
+ }
82
+ return join(dataRoot(), "traces");
83
+ }
84
+
57
85
  /**
58
86
  * Sanitize a git ref for use as a directory name.
59
87
  * Replaces characters that are invalid or confusing in path segments.
@@ -157,8 +157,11 @@ describe("updateRefs", () => {
157
157
 
158
158
  it("uses defaults when no config exists", async () => {
159
159
  const results = await updateRefs({ cwd: projectDir });
160
- // All 4 defaults are npm, so all skipped
161
- expect(results.every((r) => r.kind === "skipped")).toBe(true);
162
- expect(results).toHaveLength(4);
160
+ // All 3 defaults are git refs
161
+ expect(results).toHaveLength(3);
162
+ for (const r of results) {
163
+ // Each result is either cloned, up-to-date, or error (network)
164
+ expect(["cloned", "updated", "up-to-date", "error"]).toContain(r.kind);
165
+ }
163
166
  });
164
167
  });