@canonical/pragma-cli 0.38.0 → 0.40.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 (330) hide show
  1. package/README.md +1 -1
  2. package/dist/package.json +14 -14
  3. package/dist/pragma.conf.js +273 -176
  4. package/dist/pragma.conf.js.map +1 -1
  5. package/dist/src/capabilities/capabilities/capabilities.verb.js +2 -0
  6. package/dist/src/capabilities/capabilities/capabilities.verb.js.map +1 -1
  7. package/dist/src/capabilities/capabilities/catalog.js +47 -51
  8. package/dist/src/capabilities/capabilities/catalog.js.map +1 -1
  9. package/dist/src/capabilities/capabilities/index.js +2 -0
  10. package/dist/src/capabilities/capabilities/index.js.map +1 -1
  11. package/dist/src/capabilities/capabilities/types.js +5 -5
  12. package/dist/src/capabilities/colophon/colophon.render.js +7 -4
  13. package/dist/src/capabilities/colophon/colophon.render.js.map +1 -1
  14. package/dist/src/capabilities/colophon/colophon.verb.js +1 -0
  15. package/dist/src/capabilities/colophon/colophon.verb.js.map +1 -1
  16. package/dist/src/capabilities/config/get.verb.js +2 -0
  17. package/dist/src/capabilities/config/get.verb.js.map +1 -1
  18. package/dist/src/capabilities/config/runField.js +2 -2
  19. package/dist/src/capabilities/config/runField.js.map +1 -1
  20. package/dist/src/capabilities/config/set.verb.js +2 -0
  21. package/dist/src/capabilities/config/set.verb.js.map +1 -1
  22. package/dist/src/capabilities/config/show.verb.js +1 -0
  23. package/dist/src/capabilities/config/show.verb.js.map +1 -1
  24. package/dist/src/capabilities/config/unset.verb.js +2 -0
  25. package/dist/src/capabilities/config/unset.verb.js.map +1 -1
  26. package/dist/src/capabilities/create/constants.js +2 -2
  27. package/dist/src/capabilities/create/create.verb.js +14 -4
  28. package/dist/src/capabilities/create/create.verb.js.map +1 -1
  29. package/dist/src/capabilities/distribution.js +3 -1
  30. package/dist/src/capabilities/distribution.js.map +1 -1
  31. package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +10 -2
  32. package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
  33. package/dist/src/capabilities/doctor/doctor.verb.js +2 -0
  34. package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
  35. package/dist/src/capabilities/graph/connect.verb.js +2 -0
  36. package/dist/src/capabilities/graph/connect.verb.js.map +1 -1
  37. package/dist/src/capabilities/graph/inspect.render.js +7 -1
  38. package/dist/src/capabilities/graph/inspect.render.js.map +1 -1
  39. package/dist/src/capabilities/graph/inspect.verb.js +2 -0
  40. package/dist/src/capabilities/graph/inspect.verb.js.map +1 -1
  41. package/dist/src/capabilities/graph/query.render.js +37 -5
  42. package/dist/src/capabilities/graph/query.render.js.map +1 -1
  43. package/dist/src/capabilities/graph/query.verb.js +2 -0
  44. package/dist/src/capabilities/graph/query.verb.js.map +1 -1
  45. package/dist/src/capabilities/graph/queryText.js +28 -0
  46. package/dist/src/capabilities/graph/queryText.js.map +1 -1
  47. package/dist/src/capabilities/graph/runConnect.js +3 -3
  48. package/dist/src/capabilities/graph/runConnect.js.map +1 -1
  49. package/dist/src/capabilities/graph/runQuery.js +8 -6
  50. package/dist/src/capabilities/graph/runQuery.js.map +1 -1
  51. package/dist/src/capabilities/info/info.verb.js +2 -0
  52. package/dist/src/capabilities/info/info.verb.js.map +1 -1
  53. package/dist/src/capabilities/meta/mcp.verb.js +1 -0
  54. package/dist/src/capabilities/meta/mcp.verb.js.map +1 -1
  55. package/dist/src/capabilities/ontology/verbs.js +7 -10
  56. package/dist/src/capabilities/ontology/verbs.js.map +1 -1
  57. package/dist/src/capabilities/prompt/verbs.js +5 -4
  58. package/dist/src/capabilities/prompt/verbs.js.map +1 -1
  59. package/dist/src/capabilities/resources/provider.js +6 -3
  60. package/dist/src/capabilities/resources/provider.js.map +1 -1
  61. package/dist/src/capabilities/setup/setup.verb.js +13 -5
  62. package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
  63. package/dist/src/capabilities/shared/calls.js +16 -0
  64. package/dist/src/capabilities/shared/calls.js.map +1 -0
  65. package/dist/src/capabilities/skill/render.js +7 -5
  66. package/dist/src/capabilities/skill/render.js.map +1 -1
  67. package/dist/src/capabilities/skill/verbs.js +5 -4
  68. package/dist/src/capabilities/skill/verbs.js.map +1 -1
  69. package/dist/src/capabilities/sources/collectStatus.js +6 -1
  70. package/dist/src/capabilities/sources/collectStatus.js.map +1 -1
  71. package/dist/src/capabilities/sources/index.js +4 -3
  72. package/dist/src/capabilities/sources/index.js.map +1 -1
  73. package/dist/src/capabilities/sources/reset.render.js +37 -0
  74. package/dist/src/capabilities/sources/reset.render.js.map +1 -0
  75. package/dist/src/capabilities/sources/reset.verb.js +51 -0
  76. package/dist/src/capabilities/sources/reset.verb.js.map +1 -0
  77. package/dist/src/capabilities/sources/runReset.js +59 -0
  78. package/dist/src/capabilities/sources/runReset.js.map +1 -0
  79. package/dist/src/capabilities/sources/runUpdate.js +7 -6
  80. package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
  81. package/dist/src/capabilities/sources/status.render.js +24 -8
  82. package/dist/src/capabilities/sources/status.render.js.map +1 -1
  83. package/dist/src/capabilities/sources/status.verb.js +1 -0
  84. package/dist/src/capabilities/sources/status.verb.js.map +1 -1
  85. package/dist/src/capabilities/sources/update.verb.js +2 -0
  86. package/dist/src/capabilities/sources/update.verb.js.map +1 -1
  87. package/dist/src/capabilities/upgrade/upgrade.verb.js +1 -0
  88. package/dist/src/capabilities/upgrade/upgrade.verb.js.map +1 -1
  89. package/dist/src/capabilities/version/version.verb.js +1 -0
  90. package/dist/src/capabilities/version/version.verb.js.map +1 -1
  91. package/dist/src/constants.js +4 -3
  92. package/dist/src/constants.js.map +1 -1
  93. package/dist/src/kernel/error/index.js +1 -1
  94. package/dist/src/kernel/error/index.js.map +1 -1
  95. package/dist/src/kernel/error/recovery.js +24 -42
  96. package/dist/src/kernel/error/recovery.js.map +1 -1
  97. package/dist/src/kernel/packs/collect.js +123 -9
  98. package/dist/src/kernel/packs/collect.js.map +1 -1
  99. package/dist/src/kernel/packs/compile.js +74 -15
  100. package/dist/src/kernel/packs/compile.js.map +1 -1
  101. package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js +3 -3
  102. package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js.map +1 -1
  103. package/dist/src/kernel/packs/iri.js +2 -4
  104. package/dist/src/kernel/packs/iri.js.map +1 -1
  105. package/dist/src/kernel/packs/renderPack.js +90 -50
  106. package/dist/src/kernel/packs/renderPack.js.map +1 -1
  107. package/dist/src/kernel/packs/resolveEntity.js +202 -90
  108. package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
  109. package/dist/src/kernel/packs/runBodies.js +89 -30
  110. package/dist/src/kernel/packs/runBodies.js.map +1 -1
  111. package/dist/src/kernel/packs/schema.js +66 -12
  112. package/dist/src/kernel/packs/schema.js.map +1 -1
  113. package/dist/src/kernel/packs/sparql/buildListQuery.js +80 -13
  114. package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -1
  115. package/dist/src/kernel/packs/sparql/buildLookupQuery.js +41 -13
  116. package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
  117. package/dist/src/kernel/packs/sparql/filterValues.js +32 -23
  118. package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -1
  119. package/dist/src/kernel/packs/sparql/runSelect.js +3 -5
  120. package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
  121. package/dist/src/kernel/packs/storyRules.js +31 -4
  122. package/dist/src/kernel/packs/storyRules.js.map +1 -1
  123. package/dist/src/kernel/packs/tierScope.js +3 -3
  124. package/dist/src/kernel/packs/tierScope.js.map +1 -1
  125. package/dist/src/kernel/packs/types.js +4 -0
  126. package/dist/src/kernel/packs/types.js.map +1 -1
  127. package/dist/src/kernel/project/cli/buildProgram.js +4 -0
  128. package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
  129. package/dist/src/kernel/project/cli/dispatch.js +32 -8
  130. package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
  131. package/dist/src/kernel/project/cli/suggestNames.js +44 -1
  132. package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
  133. package/dist/src/kernel/project/cli/verbHelp.js +17 -18
  134. package/dist/src/kernel/project/cli/verbHelp.js.map +1 -1
  135. package/dist/src/kernel/project/mcp/buildServer.js +11 -4
  136. package/dist/src/kernel/project/mcp/buildServer.js.map +1 -1
  137. package/dist/src/kernel/project/mcp/envelope.js +3 -2
  138. package/dist/src/kernel/project/mcp/envelope.js.map +1 -1
  139. package/dist/src/kernel/project/mcp/instructions.js +101 -31
  140. package/dist/src/kernel/project/mcp/instructions.js.map +1 -1
  141. package/dist/src/kernel/project/mcp/registerVerb.js +59 -23
  142. package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
  143. package/dist/src/kernel/render/renderers.js +3 -3
  144. package/dist/src/kernel/render/turtle.js +21 -4
  145. package/dist/src/kernel/render/turtle.js.map +1 -1
  146. package/dist/src/kernel/runtime/graphpack/build.js +54 -1
  147. package/dist/src/kernel/runtime/graphpack/build.js.map +1 -1
  148. package/dist/src/kernel/runtime/graphpack/manifest.js +14 -0
  149. package/dist/src/kernel/runtime/graphpack/manifest.js.map +1 -1
  150. package/dist/src/kernel/runtime/graphpack/read.js +3 -5
  151. package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
  152. package/dist/src/kernel/runtime/graphpack/schemas.js +1 -0
  153. package/dist/src/kernel/runtime/graphpack/schemas.js.map +1 -1
  154. package/dist/src/kernel/runtime/loadSession.js +8 -1
  155. package/dist/src/kernel/runtime/loadSession.js.map +1 -1
  156. package/dist/src/kernel/runtime/packVersion.js +75 -0
  157. package/dist/src/kernel/runtime/packVersion.js.map +1 -0
  158. package/dist/src/kernel/runtime/readEntity.js +43 -4
  159. package/dist/src/kernel/runtime/readEntity.js.map +1 -1
  160. package/dist/src/kernel/runtime/resolveSources.js +61 -9
  161. package/dist/src/kernel/runtime/resolveSources.js.map +1 -1
  162. package/dist/src/kernel/runtime/storeReadiness.js +3 -2
  163. package/dist/src/kernel/runtime/storeReadiness.js.map +1 -1
  164. package/dist/src/kernel/spec/call.js +167 -0
  165. package/dist/src/kernel/spec/call.js.map +1 -0
  166. package/dist/src/kernel/spec/emitReference.js +9 -13
  167. package/dist/src/kernel/spec/emitReference.js.map +1 -1
  168. package/dist/src/kernel/spec/emitSurface.js +8 -1
  169. package/dist/src/kernel/spec/emitSurface.js.map +1 -1
  170. package/dist/src/kernel/spec/guidance.js +63 -0
  171. package/dist/src/kernel/spec/guidance.js.map +1 -0
  172. package/dist/src/kernel/spec/wireType.js +36 -0
  173. package/dist/src/kernel/spec/wireType.js.map +1 -0
  174. package/package.json +14 -14
  175. package/pragma.conf.ts +294 -177
  176. package/src/capabilities/block.parity.test.ts +1 -1
  177. package/src/capabilities/callRule.test.ts +147 -0
  178. package/src/capabilities/capabilities/capabilities.test.ts +47 -19
  179. package/src/capabilities/capabilities/capabilities.verb.ts +2 -0
  180. package/src/capabilities/capabilities/catalog.ts +60 -55
  181. package/src/capabilities/capabilities/index.ts +2 -0
  182. package/src/capabilities/capabilities/types.ts +16 -19
  183. package/src/capabilities/colophon/colophon.render.ts +9 -5
  184. package/src/capabilities/colophon/colophon.verb.ts +1 -0
  185. package/src/capabilities/config/get.verb.ts +2 -0
  186. package/src/capabilities/config/runField.ts +3 -3
  187. package/src/capabilities/config/set.verb.ts +3 -0
  188. package/src/capabilities/config/show.verb.ts +2 -0
  189. package/src/capabilities/config/unset.verb.ts +2 -0
  190. package/src/capabilities/create/constants.ts +2 -2
  191. package/src/capabilities/create/create.verb.ts +16 -0
  192. package/src/capabilities/create/createGrammar.test.ts +1 -1
  193. package/src/capabilities/distribution.test.ts +6 -3
  194. package/src/capabilities/distribution.ts +6 -0
  195. package/src/capabilities/doctor/checks/checkPackageRefs.ts +14 -2
  196. package/src/capabilities/doctor/doctor.test.ts +38 -1
  197. package/src/capabilities/doctor/doctor.verb.ts +2 -0
  198. package/src/capabilities/emptyRecovery.test.ts +5 -0
  199. package/src/capabilities/graph/connect.verb.ts +2 -0
  200. package/src/capabilities/graph/inspect.render.ts +9 -1
  201. package/src/capabilities/graph/inspect.test.ts +73 -0
  202. package/src/capabilities/graph/inspect.verb.ts +2 -0
  203. package/src/capabilities/graph/query.render.test.ts +35 -0
  204. package/src/capabilities/graph/query.render.ts +45 -7
  205. package/src/capabilities/graph/query.shipped.exec.test.ts +44 -0
  206. package/src/capabilities/graph/query.verb.ts +2 -0
  207. package/src/capabilities/graph/queryText.test.ts +55 -1
  208. package/src/capabilities/graph/queryText.ts +47 -0
  209. package/src/capabilities/graph/runConnect.ts +4 -5
  210. package/src/capabilities/graph/runQuery.ts +23 -9
  211. package/src/capabilities/info/info.verb.ts +2 -0
  212. package/src/capabilities/links.shipped.exec.test.ts +398 -0
  213. package/src/capabilities/listBudget.shipped.exec.test.ts +2 -2
  214. package/src/capabilities/listLookup.shipped.exec.test.ts +122 -13
  215. package/src/capabilities/listQuery.shipped.exec.test.ts +39 -16
  216. package/src/capabilities/lookupBudget.shipped.exec.test.ts +208 -0
  217. package/src/capabilities/meta/mcp.verb.ts +2 -0
  218. package/src/capabilities/ontology/ontology.test.ts +24 -0
  219. package/src/capabilities/ontology/verbs.ts +16 -12
  220. package/src/capabilities/prompt/verbs.ts +10 -4
  221. package/src/capabilities/resources/provider.ts +7 -3
  222. package/src/capabilities/resources/resources.test.ts +2 -1
  223. package/src/capabilities/setup/setup.verb.ts +16 -0
  224. package/src/capabilities/shared/calls.ts +20 -0
  225. package/src/capabilities/skill/render.ts +9 -6
  226. package/src/capabilities/skill/verbs.ts +8 -4
  227. package/src/capabilities/sources/collectStatus.ts +6 -1
  228. package/src/capabilities/sources/index.ts +4 -3
  229. package/src/capabilities/sources/reset.render.test.ts +33 -0
  230. package/src/capabilities/sources/reset.render.ts +43 -0
  231. package/src/capabilities/sources/reset.verb.ts +59 -0
  232. package/src/capabilities/sources/runReset.ts +65 -0
  233. package/src/capabilities/sources/runUpdate.ts +12 -11
  234. package/src/capabilities/sources/sources.test.ts +158 -3
  235. package/src/capabilities/sources/status.render.test.ts +63 -1
  236. package/src/capabilities/sources/status.render.ts +25 -8
  237. package/src/capabilities/sources/status.verb.ts +2 -0
  238. package/src/capabilities/sources/types.ts +26 -0
  239. package/src/capabilities/sources/update.verb.ts +3 -0
  240. package/src/capabilities/surface.test.ts +2 -2
  241. package/src/capabilities/token.parity.test.ts +3 -2
  242. package/src/capabilities/tokenGraph.shipped.exec.test.ts +14 -2
  243. package/src/capabilities/upgrade/upgrade.verb.ts +1 -0
  244. package/src/capabilities/variable.parity.test.ts +2 -1
  245. package/src/capabilities/version/version.verb.ts +1 -0
  246. package/src/capabilities/wireContract.test.ts +110 -0
  247. package/src/constants.ts +4 -3
  248. package/src/kernel/copy.test.ts +1 -1
  249. package/src/kernel/error/PragmaError.test.ts +7 -3
  250. package/src/kernel/error/index.ts +1 -1
  251. package/src/kernel/error/recovery.test.ts +52 -18
  252. package/src/kernel/error/recovery.ts +25 -46
  253. package/src/kernel/error/types.ts +1 -1
  254. package/src/kernel/packs/collect.test.ts +79 -0
  255. package/src/kernel/packs/collect.ts +151 -11
  256. package/src/kernel/packs/compile.test.ts +107 -10
  257. package/src/kernel/packs/compile.ts +100 -11
  258. package/src/kernel/packs/filteredEmpty.test.ts +22 -5
  259. package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +5 -6
  260. package/src/kernel/packs/graphqlSource.test.ts +42 -0
  261. package/src/kernel/packs/iri.ts +5 -4
  262. package/src/kernel/packs/listNotice.test.ts +1 -1
  263. package/src/kernel/packs/nounLink.test.ts +385 -0
  264. package/src/kernel/packs/renderPack.ts +137 -57
  265. package/src/kernel/packs/resolveEntity.test.ts +170 -1
  266. package/src/kernel/packs/resolveEntity.ts +281 -101
  267. package/src/kernel/packs/runBodies.ts +133 -31
  268. package/src/kernel/packs/schema.ts +77 -12
  269. package/src/kernel/packs/sparql/buildListQuery.test.ts +78 -1
  270. package/src/kernel/packs/sparql/buildListQuery.ts +106 -16
  271. package/src/kernel/packs/sparql/buildLookupQuery.ts +44 -13
  272. package/src/kernel/packs/sparql/filterValues.test.ts +36 -4
  273. package/src/kernel/packs/sparql/filterValues.ts +50 -31
  274. package/src/kernel/packs/sparql/runSelect.ts +4 -6
  275. package/src/kernel/packs/storyRules.ts +37 -4
  276. package/src/kernel/packs/tierScope.test.ts +120 -6
  277. package/src/kernel/packs/tierScope.ts +5 -7
  278. package/src/kernel/packs/toolDescription.test.ts +59 -74
  279. package/src/kernel/packs/types.ts +93 -11
  280. package/src/kernel/project/cli/buildProgram.ts +4 -0
  281. package/src/kernel/project/cli/dispatch.ts +34 -8
  282. package/src/kernel/project/cli/suggest.test.ts +77 -0
  283. package/src/kernel/project/cli/suggestNames.ts +47 -1
  284. package/src/kernel/project/cli/verbHelp.ts +16 -19
  285. package/src/kernel/project/mcp/buildServer.ts +15 -4
  286. package/src/kernel/project/mcp/envelope.ts +3 -2
  287. package/src/kernel/project/mcp/instructions.ts +123 -35
  288. package/src/kernel/project/mcp/prompts/prompts.test.ts +136 -20
  289. package/src/kernel/project/mcp/registerVerb.test.ts +28 -0
  290. package/src/kernel/project/mcp/registerVerb.ts +67 -29
  291. package/src/kernel/render/__snapshots__/renderers.test.ts.snap +1 -1
  292. package/src/kernel/render/renderers.test.ts +2 -2
  293. package/src/kernel/render/renderers.ts +3 -3
  294. package/src/kernel/render/turtle.ts +24 -4
  295. package/src/kernel/runtime/graphpack/build.ts +58 -1
  296. package/src/kernel/runtime/graphpack/graphpack.test.ts +20 -0
  297. package/src/kernel/runtime/graphpack/manifest.ts +15 -0
  298. package/src/kernel/runtime/graphpack/read.ts +4 -6
  299. package/src/kernel/runtime/graphpack/schemas.ts +1 -0
  300. package/src/kernel/runtime/graphpack/types.ts +13 -0
  301. package/src/kernel/runtime/loadSession.ts +8 -1
  302. package/src/kernel/runtime/packVersion.test.ts +61 -0
  303. package/src/kernel/runtime/packVersion.ts +84 -0
  304. package/src/kernel/runtime/readEntity.ts +61 -6
  305. package/src/kernel/runtime/resolveSources.test.ts +90 -7
  306. package/src/kernel/runtime/resolveSources.ts +91 -10
  307. package/src/kernel/runtime/storeReadiness.ts +4 -4
  308. package/src/kernel/runtime/types.ts +12 -0
  309. package/src/kernel/spec/call.test.ts +95 -0
  310. package/src/kernel/spec/call.ts +186 -0
  311. package/src/kernel/spec/emitReference.ts +9 -13
  312. package/src/kernel/spec/emitSurface.ts +9 -1
  313. package/src/kernel/spec/guidance.test.ts +49 -0
  314. package/src/kernel/spec/guidance.ts +68 -0
  315. package/src/kernel/spec/index.ts +4 -0
  316. package/src/kernel/spec/surfaceConformance.test.ts +2 -2
  317. package/src/kernel/spec/types.ts +64 -7
  318. package/src/kernel/spec/wireType.ts +53 -0
  319. package/src/testing/behavioral/errorMatrix.mcp.test.ts +2 -1
  320. package/src/testing/behavioral/journeys.firstInstall.test.ts +72 -2
  321. package/src/testing/behavioral/parity.test.ts +40 -0
  322. package/src/testing/eval/__snapshots__/eval.test.ts.snap +1 -1
  323. package/src/testing/eval/cases/assembly.ts +4 -3
  324. package/src/testing/eval/cases/stable.ts +2 -3
  325. package/src/testing/helpers/callSchema.ts +40 -0
  326. package/src/testing/helpers/parity.ts +35 -2
  327. package/src/testing/setupCallChecking.ts +30 -0
  328. package/dist/src/capabilities/capabilities/hints.js +0 -223
  329. package/dist/src/capabilities/capabilities/hints.js.map +0 -1
  330. package/src/capabilities/capabilities/hints.ts +0 -266
@@ -12,6 +12,7 @@ import { RECOVERY_CLI_PREFIX } from "../../constants.js";
12
12
  import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
13
13
  import { PragmaError } from "../error/index.js";
14
14
  import type { PragmaRuntime } from "../runtime/types.js";
15
+ import { declareVerbs } from "../spec/call.js";
15
16
  import { kebabCase } from "../spec/emitSurface.js";
16
17
  import type { VerbSpec } from "../spec/types.js";
17
18
  import { compileListable, compilePack, compileStoryModule } from "./compile.js";
@@ -362,19 +363,28 @@ describe("the grammar rejects what the compiler cannot build (PROTECTED)", () =>
362
363
  );
363
364
  });
364
365
 
365
- it("rejects an emptyRecovery.cli that names a binary, and names the change", () => {
366
- // The hint is rendered as `<consuming distribution> <cli>`, so a story
367
- // carrying the old prefixed form would render `pragma pragma sources
368
- // update`. Third-party packs are third-party DATA: they get an error that
369
- // names the grammar change, not a silently doubled string.
370
- const withCli = (cli: string) => ({
366
+ it("rejects the retired emptyRecovery.cli and a call that is a command line, naming the change", () => {
367
+ // A recovery names a CALL — a verb path and a param bag — and the consuming
368
+ // distribution spells it per surface. Third-party packs are third-party
369
+ // DATA: the old `cli` string gets an error that names the grammar change,
370
+ // and a command line in `verb` would render `pragma pragma sources update`.
371
+ const withRecovery = (recovery: Record<string, unknown>) => ({
371
372
  noun: "widget",
372
- list: { ...listShape, emptyRecovery: { message: "None.", cli } },
373
+ list: { ...listShape, emptyRecovery: { message: "None.", ...recovery } },
373
374
  });
374
- expect(parse(withCli(`${RECOVERY_CLI_PREFIX}sources update`))).toThrow(
375
- /WITHOUT the binary name/,
375
+ expect(parse(withRecovery({ cli: "sources update" }))).toThrow(
376
+ /emptyRecovery\.cli is now emptyRecovery\.call/,
376
377
  );
377
- expect(parse(withCli("sources update"))).not.toThrow();
378
+ expect(
379
+ parse(
380
+ withRecovery({
381
+ call: { verb: `${RECOVERY_CLI_PREFIX}sources update` },
382
+ }),
383
+ ),
384
+ ).toThrow(/a call names a verb path/);
385
+ expect(
386
+ parse(withRecovery({ call: { verb: "sources update" } })),
387
+ ).not.toThrow();
378
388
  });
379
389
  });
380
390
 
@@ -387,6 +397,11 @@ describe("pack compiler — SPARQL fetch path (PROTECTED)", () => {
387
397
  prefixes: PREFIXES,
388
398
  detail: "detailed",
389
399
  }));
400
+ // A miss recovers to `widget list`; the suite checks every call it renders
401
+ // against the declared verbs, and a fixture's are not the distribution's.
402
+ declareVerbs(
403
+ compilePack(WIDGET_PACK, distributionSource("bundled:widget"), PREFIXES),
404
+ );
390
405
  });
391
406
 
392
407
  afterAll(async () => {
@@ -563,6 +578,88 @@ describe("pack compiler — SPARQL fetch path (PROTECTED)", () => {
563
578
  * once, for the name resolve, and the resource listing reads that same
564
579
  * declaration. Nothing to keep in sync because there is nothing written twice.
565
580
  */
581
+ describe("a lookup that declares no disclosure can still be asked for less", () => {
582
+ /** The widget lookup with every trace of disclosure removed. */
583
+ const BARE_PACK: PackDefinition = {
584
+ noun: "widget",
585
+ lookup: {
586
+ source: "sparql",
587
+ by: "ex:name",
588
+ type: "ex:Widget",
589
+ fields: [{ name: "description", property: "ex:description" }],
590
+ expand: [
591
+ {
592
+ name: "parts",
593
+ relation: "ex:hasPart",
594
+ select: [{ name: "name", property: "ex:name" }],
595
+ },
596
+ ],
597
+ },
598
+ };
599
+ const lookupVerb = compilePack(
600
+ BARE_PACK,
601
+ distributionSource("bundled:widget"),
602
+ PREFIXES,
603
+ ).find((v) => verbKey(v.path) === "widget lookup") as VerbSpec;
604
+
605
+ const lookupAt = async (options: {
606
+ detail?: "summary" | "standard" | "detailed";
607
+ configDetail?: "summary";
608
+ }) => {
609
+ const { rt } = await buildFixtureRuntime({
610
+ ttl: TTL,
611
+ prefixes: PREFIXES,
612
+ ...(options.detail ? { detail: options.detail } : {}),
613
+ ...(options.configDetail
614
+ ? { configDetail: options.configDetail, detailOrigin: "project" }
615
+ : {}),
616
+ });
617
+ try {
618
+ const out = (await lookupVerb.run(
619
+ { name: ["Button"] },
620
+ rt,
621
+ )) as LookupOutput;
622
+ return out.results.at(0);
623
+ } finally {
624
+ (await rt.store.get()).store.dispose();
625
+ }
626
+ };
627
+
628
+ it("advertises the canonical levels, defaulting to the fullest", () => {
629
+ expect(lookupVerb.disclosure).toEqual({
630
+ levels: ["summary", "standard", "detailed"],
631
+ default: "detailed",
632
+ });
633
+ });
634
+
635
+ it("answers exactly as before when nothing is asked for", async () => {
636
+ expect(await lookupAt({})).toEqual(await lookupAt({ detail: "detailed" }));
637
+ expect((await lookupAt({}))?.parts).toEqual([{ name: "Label" }]);
638
+ });
639
+
640
+ it("is the fields alone at summary, and everything from standard", async () => {
641
+ const summary = await lookupAt({ detail: "summary" });
642
+ expect(summary).toMatchObject({ description: "A button." });
643
+ expect(summary).not.toHaveProperty("parts");
644
+ expect(await lookupAt({ detail: "standard" })).toHaveProperty("parts");
645
+ });
646
+
647
+ it("follows a configured detail, as a declared disclosure always did", async () => {
648
+ expect(await lookupAt({ configDetail: "summary" })).not.toHaveProperty(
649
+ "parts",
650
+ );
651
+ });
652
+
653
+ it("leaves a declared disclosure exactly as its author wrote it", () => {
654
+ const declared = compilePack(
655
+ WIDGET_PACK,
656
+ distributionSource("bundled:widget"),
657
+ PREFIXES,
658
+ ).find((v) => verbKey(v.path) === "widget lookup");
659
+ expect(declared?.disclosure?.default).toBe("summary");
660
+ });
661
+ });
662
+
566
663
  describe("declared listing (derived from the lookup's types)", () => {
567
664
  it("derives one collection per declared type, unweighted types at 1", () => {
568
665
  expect(
@@ -14,7 +14,7 @@
14
14
  * facade).
15
15
  */
16
16
 
17
- import { BIN_NAME } from "../../constants.js";
17
+ import { BIN_NAME, DETAIL_LEVELS } from "../../constants.js";
18
18
  import { PragmaError } from "../error/index.js";
19
19
  import { compactUri, DEFAULT_PREFIX_MAP } from "../render/index.js";
20
20
  import type { PragmaRuntime } from "../runtime/index.js";
@@ -42,8 +42,10 @@ import {
42
42
  import { storyIssues } from "./storyRules.js";
43
43
  import {
44
44
  EVERY_TIER,
45
+ type NounLookups,
45
46
  type PackDefinition,
46
47
  type PackFilter,
48
+ type PackGuidance,
47
49
  type PackList,
48
50
  type PackLookup,
49
51
  type PackPage,
@@ -74,17 +76,22 @@ const READ_CAPABILITY = {
74
76
  * @param definition - A validated pack definition.
75
77
  * @param source - Where the definition came from, for diagnostics.
76
78
  * @param prefixes - The merged prefix map used for display compaction.
79
+ * @param nouns - The other stories' lookups, which a filter naming a noun
80
+ * resolves its values through. Read at run time only.
77
81
  * @returns The compiled verbs (list, extra verbs, lookup, sample), in order.
78
82
  */
79
83
  export function compilePack(
80
84
  definition: PackDefinition,
81
85
  source: StorySource,
82
86
  prefixes: Readonly<Record<string, string>>,
87
+ nouns?: NounLookups,
83
88
  ): VerbSpec[] {
84
89
  const { noun } = definition;
85
90
  const verbs: VerbSpec[] = [];
86
91
 
87
92
  const tierScope = definition.tierScope;
93
+ // A story may declare a lookup alone; a miss must not point at a `list` it lacks.
94
+ const hasList = definition.list !== undefined;
88
95
 
89
96
  if (definition.list) {
90
97
  verbs.push(
@@ -93,8 +100,10 @@ export function compilePack(
93
100
  verb: "list",
94
101
  summary: definition.description ?? `List ${noun} entries.`,
95
102
  doc: definition.toolDescription,
103
+ ...guidanceOf(definition),
96
104
  source,
97
105
  prefixes,
106
+ ...(nouns ? { nouns } : {}),
98
107
  ...(tierScope ? { tierScope } : {}),
99
108
  }),
100
109
  );
@@ -107,19 +116,24 @@ export function compilePack(
107
116
  verb: verb.verb,
108
117
  summary: verb.description ?? `List ${noun} ${verb.verb}.`,
109
118
  doc: verb.toolDescription,
119
+ ...guidanceOf(verb),
110
120
  source,
111
121
  prefixes,
122
+ ...(nouns ? { nouns } : {}),
112
123
  ...(tierScope ? { tierScope } : {}),
113
124
  }),
114
125
  );
115
126
  }
116
127
 
117
128
  if (definition.lookup) {
129
+ // Normalised ONCE, here, so the lookup verb, its run body, both fetch lanes
130
+ // and the sample all read the same declaration.
131
+ const lookup = withDisclosure(definition.lookup);
118
132
  verbs.push(
119
- compileLookupVerb(definition.lookup, noun, source, prefixes, tierScope),
133
+ compileLookupVerb(lookup, noun, source, prefixes, hasList, tierScope),
120
134
  );
121
- if (definition.lookup.sample) {
122
- verbs.push(compileSampleVerb(definition.lookup, noun, source, prefixes));
135
+ if (lookup.sample) {
136
+ verbs.push(compileSampleVerb(lookup, noun, source, prefixes, hasList));
123
137
  }
124
138
  }
125
139
 
@@ -195,6 +209,7 @@ export function compileListable(
195
209
  * @param definition - A validated pack definition.
196
210
  * @param source - Where the definition came from, for diagnostics.
197
211
  * @param prefixes - The merged prefix map used for display compaction.
212
+ * @param nouns - As {@link compilePack}.
198
213
  * @returns The module: the compiled verbs plus the story's module-level data.
199
214
  * @throws PragmaError CONFIG_ERROR when the definition cannot be compiled,
200
215
  * naming the field and the rule.
@@ -203,6 +218,7 @@ export function compileStoryModule(
203
218
  definition: PackDefinition,
204
219
  source: StorySource,
205
220
  prefixes: Readonly<Record<string, string>>,
221
+ nouns?: NounLookups,
206
222
  ): CapabilityModule {
207
223
  const issue = storyIssues(definition)[0];
208
224
  if (issue) {
@@ -211,17 +227,47 @@ export function compileStoryModule(
211
227
  );
212
228
  }
213
229
  const listable = compileListable(definition);
214
- return {
230
+ const module: CapabilityModule = {
215
231
  name: definition.noun,
216
232
  story: true,
217
- verbs: compilePack(definition, source, prefixes),
233
+ verbs: compilePack(definition, source, prefixes, nouns),
218
234
  colophon: definition.colophon,
219
235
  ...(listable ? { mcpListable: listable } : {}),
220
236
  };
237
+ compiledFrom.set(module, { definition, source, prefixes });
238
+ return module;
239
+ }
240
+
241
+ /** What each story module was compiled from. */
242
+ const compiledFrom = new WeakMap<
243
+ CapabilityModule,
244
+ {
245
+ readonly definition: PackDefinition;
246
+ readonly source: StorySource;
247
+ readonly prefixes: Readonly<Record<string, string>>;
248
+ }
249
+ >();
250
+
251
+ /**
252
+ * The story a module was compiled from by {@link compileStoryModule}, with the
253
+ * source and prefixes it was compiled under; `undefined` for any other module.
254
+ */
255
+ export function storyOf(
256
+ module: CapabilityModule,
257
+ ): ReturnType<(typeof compiledFrom)["get"]> {
258
+ return compiledFrom.get(module);
259
+ }
260
+
261
+ /** Carry a story half's declared guidance onto its verb, omitting what is absent. */
262
+ function guidanceOf(half: PackGuidance): Pick<VerbSpec, "useWhen" | "example"> {
263
+ return {
264
+ ...(half.useWhen ? { useWhen: half.useWhen } : {}),
265
+ ...(half.example ? { example: half.example } : {}),
266
+ };
221
267
  }
222
268
 
223
269
  /** Presentation facts for one compiled list-shaped verb. */
224
- interface ListVerbMeta {
270
+ interface ListVerbMeta extends PackGuidance {
225
271
  readonly noun: string;
226
272
  readonly verb: string;
227
273
  readonly summary: string;
@@ -229,6 +275,8 @@ interface ListVerbMeta {
229
275
  readonly doc?: string;
230
276
  readonly source: StorySource;
231
277
  readonly prefixes: Readonly<Record<string, string>>;
278
+ /** The other stories' lookups, for a filter that names a noun. */
279
+ readonly nouns?: NounLookups;
232
280
  /** The noun's declared tier hierarchy, when its entities are tiered. */
233
281
  readonly tierScope?: PackTierScope;
234
282
  }
@@ -246,6 +294,7 @@ function compileListVerb(shape: PackList, meta: ListVerbMeta): VerbSpec {
246
294
  path: [meta.noun, meta.verb],
247
295
  summary: meta.summary,
248
296
  ...(meta.doc ? { doc: meta.doc } : {}),
297
+ ...guidanceOf(meta),
249
298
  params,
250
299
  output: {
251
300
  formatters: listFormatters(shape, {
@@ -272,6 +321,8 @@ function compileListVerb(shape: PackList, meta: ListVerbMeta): VerbSpec {
272
321
  runBodies().then((m) =>
273
322
  m.makeListRun(shape, {
274
323
  source: meta.source,
324
+ prefixes: meta.prefixes,
325
+ ...(meta.nouns ? { nouns: meta.nouns } : {}),
275
326
  ...(meta.tierScope ? { tierScope: meta.tierScope } : {}),
276
327
  })(params, rt),
277
328
  ),
@@ -285,6 +336,7 @@ function compileLookupVerb(
285
336
  noun: string,
286
337
  source: StorySource,
287
338
  prefixes: Readonly<Record<string, string>>,
339
+ hasList: boolean,
288
340
  tierScope?: PackTierScope,
289
341
  ): VerbSpec {
290
342
  // Derive-by-default: every lookup completes its `<name>` from the pack index
@@ -319,6 +371,7 @@ function compileLookupVerb(
319
371
  summary:
320
372
  lookup.description ?? `Look up ${noun} details by name, IRI, or glob.`,
321
373
  ...(lookup.toolDescription ? { doc: lookup.toolDescription } : {}),
374
+ ...guidanceOf(lookup),
322
375
  params: [nameParam, ...tierParams(tierScope)],
323
376
  output: { formatters: lookupFormatters(lookup, prefixes) },
324
377
  examples: [
@@ -332,13 +385,18 @@ function compileLookupVerb(
332
385
  ]
333
386
  : []),
334
387
  ],
335
- ...(lookup.disclosure
336
- ? { disclosure: disclosureSpec(lookup.disclosure) }
337
- : {}),
388
+ disclosure: disclosureSpec(lookup.disclosure),
338
389
  capability: READ_CAPABILITY,
339
390
  run: (params: Record<string, unknown>, rt: PragmaRuntime) =>
340
391
  runBodies().then((m) =>
341
- m.makeLookupRun(lookup, noun, source, prefixes, tierScope)(params, rt),
392
+ m.makeLookupRun(
393
+ lookup,
394
+ noun,
395
+ source,
396
+ prefixes,
397
+ hasList,
398
+ tierScope,
399
+ )(params, rt),
342
400
  ),
343
401
  };
344
402
  return asVerb(verb);
@@ -374,6 +432,7 @@ function compileSampleVerb(
374
432
  noun: string,
375
433
  source: StorySource,
376
434
  prefixes: Readonly<Record<string, string>>,
435
+ hasList: boolean,
377
436
  ): VerbSpec {
378
437
  const defaultCount = sampleDefaultCount(lookup);
379
438
  const config = lookup.sample === true ? undefined : lookup.sample;
@@ -396,6 +455,7 @@ function compileSampleVerb(
396
455
  config?.description ??
397
456
  `Return randomly selected complete ${noun} entries as exemplars.`,
398
457
  ...(config?.toolDescription ? { doc: config.toolDescription } : {}),
458
+ ...guidanceOf(config ?? {}),
399
459
  params: countParam,
400
460
  output: { formatters: sampleFormatters(lookup, noun, prefixes) },
401
461
  examples: [
@@ -411,12 +471,41 @@ function compileSampleVerb(
411
471
  source,
412
472
  prefixes,
413
473
  defaultCount,
474
+ hasList,
414
475
  )(params, rt),
415
476
  ),
416
477
  };
417
478
  return asVerb(verb);
418
479
  }
419
480
 
481
+ /**
482
+ * Give a lookup that declares no disclosure the canonical ladder: default
483
+ * `detailed` (so its default answer is unchanged) and untagged expands from
484
+ * `standard` (so `summary` is the fields alone, and `standard` equals
485
+ * `detailed`). A declared disclosure is returned as written.
486
+ */
487
+ function withDisclosure(lookup: PackLookup): PackLookup {
488
+ if (lookup.disclosure) return lookup;
489
+ return {
490
+ ...lookup,
491
+ disclosure: { levels: [...DETAIL_LEVELS], default: IMPUTED_DEFAULT_LEVEL },
492
+ ...(lookup.expand
493
+ ? {
494
+ expand: lookup.expand.map((expand) => ({
495
+ ...expand,
496
+ level: expand.level ?? IMPUTED_EXPAND_LEVEL,
497
+ })),
498
+ }
499
+ : {}),
500
+ };
501
+ }
502
+
503
+ /** The level an imputed disclosure answers at when none is asked for: all of it. */
504
+ const IMPUTED_DEFAULT_LEVEL = "detailed";
505
+
506
+ /** The level from which an imputed disclosure shows an untagged expand. */
507
+ const IMPUTED_EXPAND_LEVEL = "standard";
508
+
420
509
  /** Normalize a pack disclosure into a {@link DisclosureSpec} (default → base). */
421
510
  function disclosureSpec(disclosure: PackLookup["disclosure"]): DisclosureSpec {
422
511
  const levels = disclosure?.levels ?? [];
@@ -58,7 +58,7 @@ ex:slider a ex:Widget ; ex:name "Slider" ; ex:kind "input" .
58
58
  const EMPTY_RECOVERY = {
59
59
  message:
60
60
  "Widgets are recorded by the catalogue build, and a store built before it ran records none.",
61
- cli: "sources update",
61
+ call: { verb: "sources update" },
62
62
  } as const;
63
63
 
64
64
  const listShape = (uriClass: string) => ({
@@ -133,10 +133,12 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
133
133
  expect(outcome.exitCode).toBe(0);
134
134
  const said = `${outcome.stdout ?? ""}${outcome.stderr ?? ""}`;
135
135
  expect(said).toContain("No widget matches `--search zzzznotreal`.");
136
- // The filter is the news; the story's account of where widgets come from is
137
- // the other half, and a reader who mistyped nothing needs it.
136
+ // The filter is the news, with how to widen; the story's account of where
137
+ // widgets come from is kept — and the rebuild is not advised, because a
138
+ // filter that missed says nothing about the store.
139
+ expect(said).toContain("drop the argument, or loosen it");
138
140
  expect(said).toContain("recorded by the catalogue build");
139
- expect(said).toContain("pragma sources update");
141
+ expect(said).not.toContain("sources update");
140
142
  });
141
143
 
142
144
  it("every filter in force is named", async () => {
@@ -195,7 +197,7 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
195
197
  const said = `${outcome.stderr ?? ""}`;
196
198
  expect(said).toContain("No gadget matches `--kind input`.");
197
199
  expect(said).toContain("recorded by the catalogue build");
198
- expect(said).toContain("pragma sources update");
200
+ expect(said).not.toContain("sources update");
199
201
  });
200
202
 
201
203
  it("an EMPTY POPULATION unfiltered gets the kernel's own sentence", async () => {
@@ -210,4 +212,19 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
210
212
  expect(outcome.stderr).toContain("recorded by the catalogue build");
211
213
  expect(outcome.stderr).toContain("pragma sources update");
212
214
  });
215
+
216
+ it("a story with no recovery of its own: rebuild unfiltered, never when filtered", async () => {
217
+ const bare: PackDefinition = {
218
+ ...GADGET_PACK,
219
+ list: { ...listShape("ex:Gadget") },
220
+ };
221
+ const said = async (params: Record<string, unknown>): Promise<string> =>
222
+ (await executeVerb(listVerb(bare), params, REAL, as(PLAIN))).stderr ?? "";
223
+
224
+ expect(await said({})).toContain("pragma sources update");
225
+ const filtered = await said({ kind: "input" });
226
+ expect(filtered).toContain("drop the argument, or loosen it");
227
+ expect(filtered).not.toContain("sources update");
228
+ expect(filtered).not.toContain("needs building");
229
+ });
213
230
  });
@@ -14,7 +14,7 @@
14
14
  * composed only from validated pack terms and compiled schema names.
15
15
  */
16
16
 
17
- import { cliRecovery, PragmaError } from "../../error/index.js";
17
+ import { callRecovery, PragmaError } from "../../error/index.js";
18
18
  import type { PragmaRuntime } from "../../runtime/index.js";
19
19
  import type { PackChildRow, PackEntity, PackLookup } from "../types.js";
20
20
  import {
@@ -56,10 +56,9 @@ export async function fetchGraphqlLookup(
56
56
  .join("; ");
57
57
  throw PragmaError.storeUnavailable(`GraphQL lookup failed: ${messages}`, {
58
58
  // `graph inspect` needs a <uri>; `ontology list` is runnable as-is.
59
- recovery: cliRecovery(
60
- "ontology list",
59
+ recovery: callRecovery(
60
+ { verb: "ontology list" },
61
61
  "Check the loaded ontology and namespaces.",
62
- { tool: "ontology_list" },
63
62
  ),
64
63
  });
65
64
  }
@@ -72,8 +71,8 @@ export async function fetchGraphqlLookup(
72
71
  throw new PragmaError({
73
72
  code: "ENTITY_NOT_FOUND",
74
73
  message: `Cannot resolve <${entityUri}> — its rdf:type may be missing from the ontology.`,
75
- recovery: cliRecovery(
76
- `graph inspect ${entityUri}`,
74
+ recovery: callRecovery(
75
+ { verb: "graph inspect", params: { uri: entityUri } },
77
76
  "Inspect the entity's triples to check its rdf:type.",
78
77
  ),
79
78
  });
@@ -14,6 +14,7 @@ import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
14
14
  import type { PragmaRuntime, StoreSession } from "../runtime/types.js";
15
15
  import { compilePack } from "./compile.js";
16
16
  import { buildLookupDocument } from "./graphql/buildLookupDocument.js";
17
+ import { fetchGraphqlLookup } from "./graphql/fetchGraphqlLookup.js";
17
18
  import type { LookupOutput } from "./resolveEntity.js";
18
19
  import { parsePackDefinition } from "./schema.js";
19
20
  import type { PackDefinition, PackLookup } from "./types.js";
@@ -320,6 +321,47 @@ describe("GraphQL engine — against the compiled fixture schema (PROTECTED)", (
320
321
 
321
322
  const lookup = GBLOCK.lookup as PackLookup;
322
323
 
324
+ /** The fixture runtime with its GraphQL executor replaced by a canned answer. */
325
+ const answering = (answer: unknown): PragmaRuntime =>
326
+ ({
327
+ ...rt,
328
+ query: { ...rt.query, graphql: async () => answer },
329
+ }) as PragmaRuntime;
330
+ const fetchWith = (answer: unknown) =>
331
+ fetchGraphqlLookup(
332
+ answering(answer),
333
+ lookup,
334
+ "https://ds.canonical.com/x",
335
+ "X",
336
+ "t",
337
+ BLOCK_PREFIXES,
338
+ );
339
+
340
+ it("an execution error recovers to the namespace list, in both spellings", async () => {
341
+ await expect(
342
+ fetchWith({ errors: [{ message: "boom" }] }),
343
+ ).rejects.toMatchObject({
344
+ code: "STORE_UNAVAILABLE",
345
+ recovery: {
346
+ cli: "pragma ontology list",
347
+ mcp: { tool: "ontology_list", params: {} },
348
+ },
349
+ });
350
+ });
351
+
352
+ it("a resolved IRI with no typed node recovers to inspecting THAT entity", async () => {
353
+ await expect(fetchWith({ data: { node: null } })).rejects.toMatchObject({
354
+ code: "ENTITY_NOT_FOUND",
355
+ recovery: {
356
+ cli: "pragma graph inspect https://ds.canonical.com/x",
357
+ mcp: {
358
+ tool: "graph_inspect",
359
+ params: { uri: "https://ds.canonical.com/x" },
360
+ },
361
+ },
362
+ });
363
+ });
364
+
323
365
  it("generates one document with derived names, Relay envelopes, subtype scoping", () => {
324
366
  const plan = buildLookupDocument(lookup, schema, "t");
325
367
  expect(plan.source).toContain("query PackLookup($uri: ID!)");
@@ -7,7 +7,7 @@
7
7
  * before it can be interpolated into a generated `<iri>` query token.
8
8
  */
9
9
 
10
- import { cliRecovery, PragmaError } from "../error/index.js";
10
+ import { callRecovery, PragmaError } from "../error/index.js";
11
11
 
12
12
  /** Characters not allowed inside a SPARQL `<IRI>`. */
13
13
  const UNSAFE_IRI_PATTERN = /[<>"{}|\\^`\s]/;
@@ -86,9 +86,10 @@ function tryResolveUri(
86
86
 
87
87
  return PragmaError.invalidInput("prefix", prefix, {
88
88
  validOptions: Object.keys(prefixes),
89
- recovery: cliRecovery("ontology list", "List known ontology prefixes.", {
90
- tool: "ontology_list",
91
- }),
89
+ recovery: callRecovery(
90
+ { verb: "ontology list" },
91
+ "List known ontology prefixes.",
92
+ ),
92
93
  });
93
94
  }
94
95
 
@@ -46,7 +46,7 @@ ex:slider a ex:Widget ; ex:name "Slider" ; ex:kind "input" .
46
46
  /** The recovery a story authors for an EMPTY POPULATION — never for a filter. */
47
47
  const EMPTY_RECOVERY = {
48
48
  message: "No widgets in the store.",
49
- cli: "sources update",
49
+ call: { verb: "sources update" },
50
50
  } as const;
51
51
 
52
52
  const WIDGET_LIST = {