@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,18 +1,17 @@
1
- import { createInterface } from "node:readline";
2
1
  import {
2
+ answerPromptWithDefaults,
3
3
  type CommandResult,
4
4
  createExitResult,
5
5
  createOutputResult,
6
6
  formatEffectLine,
7
7
  isVisibleEffect,
8
+ runGeneratorTask,
8
9
  } from "@canonical/cli-core";
9
- import {
10
- dryRun,
11
- type Effect,
12
- runTask,
13
- runUndo,
14
- type Task,
15
- } from "@canonical/task";
10
+ import { dryRun, type Effect, type Task } from "@canonical/task";
11
+ import { runUndo } from "@canonical/task/node";
12
+ import createInteractivePromptSession, {
13
+ type InteractivePromptSession,
14
+ } from "../../shared/createInteractivePromptSession.js";
16
15
  import type { LogLevel } from "../types.js";
17
16
 
18
17
  /** Options controlling how {@link runSetupTask} executes. */
@@ -26,55 +25,41 @@ export interface SetupTaskOptions {
26
25
  }
27
26
 
28
27
  /**
29
- * Auto-confirm prompt handler for `--yes` mode.
30
- *
31
- * @param effect - A Prompt effect to resolve.
32
- * @returns The default value for the prompt type.
28
+ * Pick the prompt handler for a run: auto-confirm defaults under `--yes`, else
29
+ * an interactive readline session (whose lifetime the caller owns via the
30
+ * returned `dispose`).
33
31
  */
34
- function autoConfirmHandler(
35
- effect: Effect & { _tag: "Prompt" },
36
- ): Promise<unknown> {
37
- const q = effect.question;
38
- if (q.type === "confirm") return Promise.resolve(q.default ?? true);
39
- if (q.type === "select")
40
- return Promise.resolve(q.default ?? q.choices[0]?.value);
41
- if (q.type === "multiselect") return Promise.resolve(q.default ?? []);
42
- return Promise.resolve(q.default ?? "");
32
+ function selectPromptHandler(yes: boolean): {
33
+ handler: (effect: Effect & { _tag: "Prompt" }) => Promise<unknown>;
34
+ wasInterrupted: () => boolean;
35
+ dispose: () => void;
36
+ } {
37
+ if (yes) {
38
+ return {
39
+ handler: answerPromptWithDefaults,
40
+ wasInterrupted: () => false,
41
+ dispose: () => {},
42
+ };
43
+ }
44
+ const session: InteractivePromptSession = createInteractivePromptSession();
45
+ return {
46
+ handler: session.answerPrompt,
47
+ wasInterrupted: session.wasInterrupted,
48
+ dispose: session.dispose,
49
+ };
43
50
  }
44
51
 
45
52
  /**
46
- * Interactive prompt handler using readline on stdin/stderr.
47
- * Supports confirm prompts; other types fall back to defaults.
48
- *
49
- * @param effect - A Prompt effect to resolve interactively.
50
- * @returns The user's answer.
53
+ * Build a task log sink that writes to stderr, hiding debug lines unless
54
+ * verbose is set.
51
55
  */
52
- async function interactivePromptHandler(
53
- effect: Effect & { _tag: "Prompt" },
54
- ): Promise<unknown> {
55
- const q = effect.question;
56
-
57
- if (q.type === "confirm") {
58
- const defaultYes = q.default !== false;
59
- const hint = defaultYes ? "Y/n" : "y/N";
60
- const rl = createInterface({
61
- input: process.stdin,
62
- output: process.stderr,
63
- });
64
-
65
- const answer = await new Promise<string>((resolve) => {
66
- rl.question(`${q.message} [${hint}] `, (ans) => {
67
- rl.close();
68
- resolve(ans.trim());
69
- });
70
- });
71
-
72
- if (answer === "") return defaultYes;
73
- return answer.toLowerCase().startsWith("y");
74
- }
75
-
76
- // Non-confirm prompts fall back to defaults in D15
77
- return q.default;
56
+ function createStderrLogger(
57
+ verbose: boolean,
58
+ ): (level: LogLevel, message: string) => void {
59
+ return (level, message) => {
60
+ if (level === "debug" && !verbose) return;
61
+ process.stderr.write(`${message}\n`);
62
+ };
78
63
  }
79
64
 
80
65
  /**
@@ -150,7 +135,8 @@ function formatDryRunJson(effects: readonly Effect[]): string {
150
135
  * Supports three execution modes:
151
136
  * - `--dry-run`: collects effects without executing, formats for display.
152
137
  * - `--undo`: walks the task tree, collects undo operations, executes in reverse.
153
- * - default: interactive execution with readline-based prompts on stderr.
138
+ * - default: execution through {@link runGeneratorTask}, with readline-based
139
+ * prompts on stderr.
154
140
  *
155
141
  * @param task - The setup Task to execute.
156
142
  * @param options - Execution options (dryRun, undo, yes, verbose, llm, format).
@@ -182,14 +168,12 @@ export default async function runSetupTask(
182
168
 
183
169
  // Undo mode: walk the task tree, collect undos, execute in reverse
184
170
  if (options.undo) {
185
- const promptHandler = options.yes
186
- ? autoConfirmHandler
187
- : interactivePromptHandler;
188
-
189
- const onLog = (level: LogLevel, message: string): void => {
190
- if (level === "debug" && !verbose) return;
191
- process.stderr.write(`${message}\n`);
192
- };
171
+ const {
172
+ handler: promptHandler,
173
+ wasInterrupted,
174
+ dispose,
175
+ } = selectPromptHandler(options.yes ?? false);
176
+ const onLog = createStderrLogger(verbose);
193
177
 
194
178
  try {
195
179
  const result = await runUndo(task, { promptHandler, onLog });
@@ -202,28 +186,36 @@ export default async function runSetupTask(
202
186
  }
203
187
  return createExitResult(0);
204
188
  } catch (err) {
189
+ if (wasInterrupted()) {
190
+ return createExitResult(130);
191
+ }
205
192
  const message = err instanceof Error ? err.message : String(err);
206
193
  process.stderr.write(`Undo failed: ${message}\n`);
207
194
  return createExitResult(1);
195
+ } finally {
196
+ dispose();
208
197
  }
209
198
  }
210
199
 
211
200
  // Production execution
212
- const promptHandler = options.yes
213
- ? autoConfirmHandler
214
- : interactivePromptHandler;
215
-
216
- const onLog = (level: LogLevel, message: string): void => {
217
- if (level === "debug" && !verbose) return;
218
- process.stderr.write(`${message}\n`);
219
- };
201
+ const {
202
+ handler: promptHandler,
203
+ wasInterrupted,
204
+ dispose,
205
+ } = selectPromptHandler(options.yes ?? false);
206
+ const onLog = createStderrLogger(verbose);
220
207
 
221
208
  try {
222
- await runTask(task, { promptHandler, onLog });
209
+ await runGeneratorTask(task, { promptHandler, onLog });
223
210
  return createExitResult(0);
224
211
  } catch (err) {
212
+ if (wasInterrupted()) {
213
+ return createExitResult(130);
214
+ }
225
215
  const message = err instanceof Error ? err.message : String(err);
226
216
  process.stderr.write(`Setup failed: ${message}\n`);
227
217
  return createExitResult(1);
218
+ } finally {
219
+ dispose();
228
220
  }
229
221
  }
@@ -10,7 +10,12 @@ const mockExists =
10
10
  function mocks(
11
11
  existsPredicate: (path: string) => boolean,
12
12
  ): Map<string, (effect: Effect) => unknown> {
13
- return new Map([["Exists", mockExists(existsPredicate)]]);
13
+ return new Map<string, (effect: Effect) => unknown>([
14
+ ["Exists", mockExists(existsPredicate)],
15
+ // An existing config reads back as an empty-but-valid JSON object, so a
16
+ // write merges into it rather than failing closed on the dry-run placeholder.
17
+ ["ReadFile", () => "{}"],
18
+ ]);
14
19
  }
15
20
 
16
21
  describe("setupMcp", () => {
@@ -1,85 +1,127 @@
1
1
  /**
2
- * Boot a ke store from pragma.config.json sources.
2
+ * Boot a ke store from resolved semantic packages.
3
3
  *
4
- * Reads configuration, resolves sources (defaults or overridden),
5
- * creates the store with registered prefixes, and wraps errors.
4
+ * Resolves packages via the loader chain (local > git > bundled),
5
+ * then loads all graph content into the store.
6
6
  *
7
7
  * @note Impure — reads filesystem, creates ke store.
8
8
  */
9
9
 
10
- import { existsSync } from "node:fs";
11
- import { join } from "node:path";
12
- import type { SourceSpec, Store } from "@canonical/ke";
13
- import { createStore } from "@canonical/ke";
10
+ import {
11
+ createStore,
12
+ definePlugin,
13
+ type Plugin,
14
+ type SourceSpec,
15
+ type Store,
16
+ } from "@canonical/ke";
14
17
  import { PragmaError } from "../../error/index.js";
15
18
  import type { PackageRef } from "../refs/operations/parseRef.js";
16
- import { resolvePackages } from "./packages.js";
19
+ import { parsePackageEntry } from "../refs/operations/parseRef.js";
20
+ import {
21
+ createBundledLoader,
22
+ createGitLoader,
23
+ createLocalLoader,
24
+ } from "./loaders/index.js";
25
+ import { DEFAULT_PACKAGES } from "./packages.js";
17
26
  import { PREFIX_MAP } from "./prefixes.js";
18
-
19
- /**
20
- * Convention-based TTL directories to scan in each package.
21
- * Only directories that exist are globbed — packages that lack
22
- * a `data/` or `definitions/` dir are silently skipped.
23
- */
24
- const TTL_DIRS: readonly { dir: string; glob: string }[] = [
25
- { dir: "definitions", glob: "definitions/**/*.ttl" },
26
- { dir: "data", glob: "data/**/*.ttl" },
27
- ];
28
-
29
- /**
30
- * Resolve default TTL sources from resolved packages.
31
- *
32
- * Uses convention-based TTL discovery: definitions and data globs
33
- * relative to each package root. Only adds globs for directories
34
- * that actually exist in the package.
35
- *
36
- * @param refs - Parsed package references. Omit for defaults.
37
- */
38
- export function defaultSources(refs?: ReadonlyArray<PackageRef>): SourceSpec[] {
39
- const sources: SourceSpec[] = [];
40
- const resolved = resolvePackages(refs);
41
-
42
- for (const { dir } of resolved) {
43
- for (const entry of TTL_DIRS) {
44
- if (existsSync(join(dir, entry.dir))) {
45
- sources.push(join(dir, entry.glob));
46
- }
47
- }
48
- }
49
-
50
- return sources;
51
- }
27
+ import type { SemanticPackage } from "./semanticPackage.js";
28
+ import { resolveSemanticPackages } from "./semanticPackage.js";
52
29
 
53
30
  export interface BootStoreOptions {
54
- /** Override sources (skip filesystem resolution). */
31
+ /** Override sources (skip package resolution — for testing). */
55
32
  sources?: SourceSpec[];
56
33
  /** Working directory for resolving relative paths. */
57
34
  cwd?: string;
58
35
  /** Cache path for serialized store. */
59
36
  cache?: string;
60
- /** Parsed package references for ref-based resolution. */
37
+ /** Parsed package references for loader-based resolution. */
61
38
  refs?: ReadonlyArray<PackageRef>;
39
+ /** Enable query tracing (from config). Env var PRAGMA_TRACE=1 overrides. */
40
+ trace?: boolean;
41
+ /** Additional namespace prefixes merged over the built-in prefix map. */
42
+ prefixes?: Readonly<Record<string, string>>;
43
+ }
44
+
45
+ export interface BootResult {
46
+ /** The initialized ke store. */
47
+ readonly store: Store;
48
+ /** Resolved semantic packages (empty when sources override is used). */
49
+ readonly packages: readonly SemanticPackage[];
62
50
  }
63
51
 
64
52
  /**
65
53
  * Boot a ke store from configuration.
66
54
  *
55
+ * When `sources` is provided, uses them directly (testing path).
56
+ * Otherwise, resolves packages via the loader chain and loads their
57
+ * graph content into the store.
58
+ *
67
59
  * @throws PragmaError with code STORE_ERROR on failure.
68
60
  */
69
61
  export async function bootStore(
70
62
  options: BootStoreOptions = {},
71
- ): Promise<Store> {
72
- const sources = options.sources ?? defaultSources(options.refs);
73
-
63
+ ): Promise<BootResult> {
64
+ const prefixes = { ...PREFIX_MAP, ...options.prefixes };
74
65
  try {
66
+ // Testing/programmatic override — use explicit sources
67
+ if (options.sources) {
68
+ const store = await createStore({
69
+ sources: options.sources,
70
+ prefixes,
71
+ cache: options.cache,
72
+ cwd: options.cwd,
73
+ });
74
+ return { store, packages: [] };
75
+ }
76
+
77
+ // Resolve packages via loader chain: local > git > bundled
78
+ const refs =
79
+ options.refs && options.refs.length > 0
80
+ ? options.refs
81
+ : DEFAULT_PACKAGES.map(parsePackageEntry);
82
+ // Precedence: local (file:// + node_modules) > git cache > bundled
83
+ const loaders = [
84
+ createLocalLoader(),
85
+ createGitLoader(),
86
+ createBundledLoader(),
87
+ ];
88
+ const packages = await resolveSemanticPackages(refs, loaders);
89
+
90
+ // Collect all graph content from resolved packages
91
+ const allGraphs = packages.flatMap((pkg) => pkg.graphs);
92
+
93
+ // Use a ke plugin to load graph content during store creation.
94
+ // The onReady hook has access to ctx.load() which loads raw content.
95
+ const graphLoaderPlugin = definePlugin({
96
+ name: "pragma-graph-loader",
97
+ onReady(ctx) {
98
+ for (const graph of allGraphs) {
99
+ ctx.load(graph.content, { format: graph.format });
100
+ }
101
+ },
102
+ });
103
+
104
+ // biome-ignore lint: Plugin generic variance requires explicit unknown
105
+ const plugins: Plugin<any>[] = [graphLoaderPlugin];
106
+ const traceEnabled =
107
+ process.env.PRAGMA_TRACE === "1" || options.trace === true;
108
+ if (traceEnabled) {
109
+ const { createTracePlugin } = await import("../trace/tracePlugin.js");
110
+ const { traceDir } = await import("../refs/operations/paths.js");
111
+ plugins.push(createTracePlugin({ traceDir: traceDir() }));
112
+ }
113
+
75
114
  const store = await createStore({
76
- sources,
77
- prefixes: PREFIX_MAP,
115
+ sources: [],
116
+ prefixes,
78
117
  cache: options.cache,
79
118
  cwd: options.cwd,
119
+ plugins,
80
120
  });
81
- return store;
121
+
122
+ return { store, packages };
82
123
  } catch (error) {
124
+ if (error instanceof PragmaError) throw error;
83
125
  throw PragmaError.storeError(
84
126
  error instanceof Error ? error.message : String(error),
85
127
  {
@@ -18,4 +18,15 @@ describe("compactUri", () => {
18
18
  "https://example.com/thing",
19
19
  );
20
20
  });
21
+
22
+ it("picks the longest matching namespace when namespaces overlap", () => {
23
+ const overlapping = {
24
+ base: "https://ex.org/",
25
+ sub: "https://ex.org/sub/",
26
+ } as const;
27
+ // Both `base` and `sub` are prefixes of the URI; the longer wins.
28
+ expect(compactUri("https://ex.org/sub/Thing", overlapping)).toBe(
29
+ "sub:Thing",
30
+ );
31
+ });
21
32
  });
@@ -1,16 +1,21 @@
1
1
  /**
2
- * Convert a full URI to its compact prefixed form when a matching prefix exists.
3
- * Falls back to the original URI when no namespace matches.
2
+ * Convert a full URI to its compact prefixed form using the longest matching
3
+ * namespace. When two registered namespaces are both prefixes of the URI
4
+ * (e.g. a base namespace and a sub-namespace), the longer — more specific —
5
+ * one wins. Falls back to the original URI when no namespace matches.
4
6
  */
5
7
  export default function compactUri(
6
8
  fullUri: string,
7
9
  prefixes: Readonly<Record<string, string>>,
8
10
  ): string {
11
+ let best: { prefix: string; namespace: string } | undefined;
9
12
  for (const [prefix, namespace] of Object.entries(prefixes)) {
10
- if (fullUri.startsWith(namespace)) {
11
- return `${prefix}:${fullUri.slice(namespace.length)}`;
13
+ if (!fullUri.startsWith(namespace)) continue;
14
+ if (best === undefined || namespace.length > best.namespace.length) {
15
+ best = { prefix, namespace };
12
16
  }
13
17
  }
14
18
 
15
- return fullUri;
19
+ if (best === undefined) return fullUri;
20
+ return `${best.prefix}:${fullUri.slice(best.namespace.length)}`;
16
21
  }
@@ -7,10 +7,10 @@
7
7
  * cli-core remains unaware of Store or FilterConfig.
8
8
  */
9
9
 
10
- import type { GlobalFlags, InteractiveHandler } from "@canonical/cli-core";
10
+ import type { GlobalFlags, PromptSessionFactory } from "@canonical/cli-core";
11
11
  import type { PragmaRuntime } from "./types/index.js";
12
12
 
13
13
  export interface PragmaContext extends PragmaRuntime {
14
14
  readonly globalFlags: GlobalFlags;
15
- readonly interactive?: InteractiveHandler | undefined;
15
+ readonly promptSession?: PromptSessionFactory | undefined;
16
16
  }
@@ -50,13 +50,25 @@ export interface ListResult<T> {
50
50
  | { readonly level: "detailed" };
51
51
  }
52
52
 
53
+ /** Aggregate metadata about a multi-query lookup. */
54
+ export interface LookupResultMeta {
55
+ /**
56
+ * Number of queries that failed with an unexpected (non-Pragma) error.
57
+ * Each such failure is also present in `errors` with code `INTERNAL_ERROR`.
58
+ */
59
+ readonly internalErrorCount: number;
60
+ }
61
+
53
62
  export interface LookupResult<T> {
54
63
  readonly results: readonly T[];
55
64
  readonly errors: readonly {
56
65
  query: string;
57
66
  code: string;
58
67
  message: string;
68
+ suggestions?: readonly string[];
59
69
  }[];
70
+ /** Populated by `lookupMany`; may be absent on hand-built results. */
71
+ readonly meta?: LookupResultMeta;
60
72
  }
61
73
 
62
74
  export interface ShowContract<T> {