@canonical/pragma-cli 0.38.0 → 0.42.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 (365) hide show
  1. package/README.md +3 -3
  2. package/dist/package.json +16 -16
  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/colophon/markdownTerminal.js.map +1 -1
  17. package/dist/src/capabilities/config/get.verb.js +2 -0
  18. package/dist/src/capabilities/config/get.verb.js.map +1 -1
  19. package/dist/src/capabilities/config/runField.js +2 -2
  20. package/dist/src/capabilities/config/runField.js.map +1 -1
  21. package/dist/src/capabilities/config/set.verb.js +2 -0
  22. package/dist/src/capabilities/config/set.verb.js.map +1 -1
  23. package/dist/src/capabilities/config/show.render.js.map +1 -1
  24. package/dist/src/capabilities/config/show.verb.js +1 -0
  25. package/dist/src/capabilities/config/show.verb.js.map +1 -1
  26. package/dist/src/capabilities/config/unset.verb.js +2 -0
  27. package/dist/src/capabilities/config/unset.verb.js.map +1 -1
  28. package/dist/src/capabilities/create/constants.js +8 -5
  29. package/dist/src/capabilities/create/constants.js.map +1 -1
  30. package/dist/src/capabilities/create/create.render.js.map +1 -1
  31. package/dist/src/capabilities/create/create.verb.js +36 -7
  32. package/dist/src/capabilities/create/create.verb.js.map +1 -1
  33. package/dist/src/capabilities/create/createSurface.generated.js +22 -0
  34. package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
  35. package/dist/src/capabilities/create/index.js +1 -1
  36. package/dist/src/capabilities/create/pickGenerator.js +1 -0
  37. package/dist/src/capabilities/create/pickGenerator.js.map +1 -1
  38. package/dist/src/capabilities/distribution.js +3 -1
  39. package/dist/src/capabilities/distribution.js.map +1 -1
  40. package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +10 -2
  41. package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
  42. package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
  43. package/dist/src/capabilities/doctor/doctor.verb.js +2 -0
  44. package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
  45. package/dist/src/capabilities/graph/connect.verb.js +2 -0
  46. package/dist/src/capabilities/graph/connect.verb.js.map +1 -1
  47. package/dist/src/capabilities/graph/inspect.render.js +7 -1
  48. package/dist/src/capabilities/graph/inspect.render.js.map +1 -1
  49. package/dist/src/capabilities/graph/inspect.verb.js +2 -0
  50. package/dist/src/capabilities/graph/inspect.verb.js.map +1 -1
  51. package/dist/src/capabilities/graph/query.render.js +37 -5
  52. package/dist/src/capabilities/graph/query.render.js.map +1 -1
  53. package/dist/src/capabilities/graph/query.verb.js +2 -0
  54. package/dist/src/capabilities/graph/query.verb.js.map +1 -1
  55. package/dist/src/capabilities/graph/queryText.js +28 -0
  56. package/dist/src/capabilities/graph/queryText.js.map +1 -1
  57. package/dist/src/capabilities/graph/runConnect.js +3 -3
  58. package/dist/src/capabilities/graph/runConnect.js.map +1 -1
  59. package/dist/src/capabilities/graph/runQuery.js +8 -6
  60. package/dist/src/capabilities/graph/runQuery.js.map +1 -1
  61. package/dist/src/capabilities/info/info.verb.js +2 -0
  62. package/dist/src/capabilities/info/info.verb.js.map +1 -1
  63. package/dist/src/capabilities/meta/mcp.verb.js +1 -0
  64. package/dist/src/capabilities/meta/mcp.verb.js.map +1 -1
  65. package/dist/src/capabilities/ontology/verbs.js +7 -10
  66. package/dist/src/capabilities/ontology/verbs.js.map +1 -1
  67. package/dist/src/capabilities/prompt/verbs.js +5 -4
  68. package/dist/src/capabilities/prompt/verbs.js.map +1 -1
  69. package/dist/src/capabilities/resources/provider.js +6 -3
  70. package/dist/src/capabilities/resources/provider.js.map +1 -1
  71. package/dist/src/capabilities/setup/operations/writability.js.map +1 -1
  72. package/dist/src/capabilities/setup/plan.render.js.map +1 -1
  73. package/dist/src/capabilities/setup/setup.verb.js +13 -5
  74. package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
  75. package/dist/src/capabilities/shared/calls.js +16 -0
  76. package/dist/src/capabilities/shared/calls.js.map +1 -0
  77. package/dist/src/capabilities/shared/packageManager.js.map +1 -1
  78. package/dist/src/capabilities/skill/discover.js.map +1 -1
  79. package/dist/src/capabilities/skill/render.js +7 -5
  80. package/dist/src/capabilities/skill/render.js.map +1 -1
  81. package/dist/src/capabilities/skill/verbs.js +5 -4
  82. package/dist/src/capabilities/skill/verbs.js.map +1 -1
  83. package/dist/src/capabilities/sources/collectStatus.js +6 -1
  84. package/dist/src/capabilities/sources/collectStatus.js.map +1 -1
  85. package/dist/src/capabilities/sources/index.js +4 -3
  86. package/dist/src/capabilities/sources/index.js.map +1 -1
  87. package/dist/src/capabilities/sources/reset.render.js +37 -0
  88. package/dist/src/capabilities/sources/reset.render.js.map +1 -0
  89. package/dist/src/capabilities/sources/reset.verb.js +51 -0
  90. package/dist/src/capabilities/sources/reset.verb.js.map +1 -0
  91. package/dist/src/capabilities/sources/runReset.js +59 -0
  92. package/dist/src/capabilities/sources/runReset.js.map +1 -0
  93. package/dist/src/capabilities/sources/runUpdate.js +7 -6
  94. package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
  95. package/dist/src/capabilities/sources/status.render.js +24 -8
  96. package/dist/src/capabilities/sources/status.render.js.map +1 -1
  97. package/dist/src/capabilities/sources/status.verb.js +1 -0
  98. package/dist/src/capabilities/sources/status.verb.js.map +1 -1
  99. package/dist/src/capabilities/sources/update.verb.js +2 -0
  100. package/dist/src/capabilities/sources/update.verb.js.map +1 -1
  101. package/dist/src/capabilities/upgrade/upgrade.verb.js +1 -0
  102. package/dist/src/capabilities/upgrade/upgrade.verb.js.map +1 -1
  103. package/dist/src/capabilities/version/version.verb.js +1 -0
  104. package/dist/src/capabilities/version/version.verb.js.map +1 -1
  105. package/dist/src/constants.js +4 -3
  106. package/dist/src/constants.js.map +1 -1
  107. package/dist/src/kernel/completion/complete.js.map +1 -1
  108. package/dist/src/kernel/completion/emitScripts.js.map +1 -1
  109. package/dist/src/kernel/completion/parse.js.map +1 -1
  110. package/dist/src/kernel/completion/rank.js.map +1 -1
  111. package/dist/src/kernel/completion/resolve.js.map +1 -1
  112. package/dist/src/kernel/config/readConfig.js.map +1 -1
  113. package/dist/src/kernel/error/PragmaError.js.map +1 -1
  114. package/dist/src/kernel/error/index.js +1 -1
  115. package/dist/src/kernel/error/index.js.map +1 -1
  116. package/dist/src/kernel/error/recovery.js +24 -42
  117. package/dist/src/kernel/error/recovery.js.map +1 -1
  118. package/dist/src/kernel/packs/collect.js +123 -9
  119. package/dist/src/kernel/packs/collect.js.map +1 -1
  120. package/dist/src/kernel/packs/compile.js +74 -15
  121. package/dist/src/kernel/packs/compile.js.map +1 -1
  122. package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js +3 -3
  123. package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js.map +1 -1
  124. package/dist/src/kernel/packs/iri.js +2 -4
  125. package/dist/src/kernel/packs/iri.js.map +1 -1
  126. package/dist/src/kernel/packs/renderPack.js +90 -50
  127. package/dist/src/kernel/packs/renderPack.js.map +1 -1
  128. package/dist/src/kernel/packs/resolveEntity.js +202 -90
  129. package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
  130. package/dist/src/kernel/packs/runBodies.js +89 -30
  131. package/dist/src/kernel/packs/runBodies.js.map +1 -1
  132. package/dist/src/kernel/packs/schema.js +66 -12
  133. package/dist/src/kernel/packs/schema.js.map +1 -1
  134. package/dist/src/kernel/packs/sparql/buildListQuery.js +80 -13
  135. package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -1
  136. package/dist/src/kernel/packs/sparql/buildLookupQuery.js +41 -13
  137. package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
  138. package/dist/src/kernel/packs/sparql/filterValues.js +32 -23
  139. package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -1
  140. package/dist/src/kernel/packs/sparql/runSelect.js +3 -5
  141. package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
  142. package/dist/src/kernel/packs/storyRules.js +31 -4
  143. package/dist/src/kernel/packs/storyRules.js.map +1 -1
  144. package/dist/src/kernel/packs/tierScope.js +3 -3
  145. package/dist/src/kernel/packs/tierScope.js.map +1 -1
  146. package/dist/src/kernel/packs/types.js +4 -0
  147. package/dist/src/kernel/packs/types.js.map +1 -1
  148. package/dist/src/kernel/project/cli/buildProgram.js +4 -0
  149. package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
  150. package/dist/src/kernel/project/cli/dispatch.js +32 -8
  151. package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
  152. package/dist/src/kernel/project/cli/globalFlags.js.map +1 -1
  153. package/dist/src/kernel/project/cli/suggestNames.js +44 -1
  154. package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
  155. package/dist/src/kernel/project/cli/verbHelp.js +17 -18
  156. package/dist/src/kernel/project/cli/verbHelp.js.map +1 -1
  157. package/dist/src/kernel/project/mcp/buildServer.js +11 -4
  158. package/dist/src/kernel/project/mcp/buildServer.js.map +1 -1
  159. package/dist/src/kernel/project/mcp/envelope.js +3 -2
  160. package/dist/src/kernel/project/mcp/envelope.js.map +1 -1
  161. package/dist/src/kernel/project/mcp/instructions.js +101 -31
  162. package/dist/src/kernel/project/mcp/instructions.js.map +1 -1
  163. package/dist/src/kernel/project/mcp/registerVerb.js +59 -23
  164. package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
  165. package/dist/src/kernel/render/envelope.js.map +1 -1
  166. package/dist/src/kernel/render/renderers.js +3 -3
  167. package/dist/src/kernel/render/renderers.js.map +1 -1
  168. package/dist/src/kernel/render/turtle.js +21 -4
  169. package/dist/src/kernel/render/turtle.js.map +1 -1
  170. package/dist/src/kernel/runtime/boot.js.map +1 -1
  171. package/dist/src/kernel/runtime/graphpack/build.js +54 -1
  172. package/dist/src/kernel/runtime/graphpack/build.js.map +1 -1
  173. package/dist/src/kernel/runtime/graphpack/manifest.js +14 -0
  174. package/dist/src/kernel/runtime/graphpack/manifest.js.map +1 -1
  175. package/dist/src/kernel/runtime/graphpack/read.js +3 -5
  176. package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
  177. package/dist/src/kernel/runtime/graphpack/schemas.js +1 -0
  178. package/dist/src/kernel/runtime/graphpack/schemas.js.map +1 -1
  179. package/dist/src/kernel/runtime/loadSession.js +8 -1
  180. package/dist/src/kernel/runtime/loadSession.js.map +1 -1
  181. package/dist/src/kernel/runtime/packVersion.js +75 -0
  182. package/dist/src/kernel/runtime/packVersion.js.map +1 -0
  183. package/dist/src/kernel/runtime/readEntity.js +43 -4
  184. package/dist/src/kernel/runtime/readEntity.js.map +1 -1
  185. package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
  186. package/dist/src/kernel/runtime/resolveSources.js +61 -9
  187. package/dist/src/kernel/runtime/resolveSources.js.map +1 -1
  188. package/dist/src/kernel/runtime/storeReadiness.js +3 -2
  189. package/dist/src/kernel/runtime/storeReadiness.js.map +1 -1
  190. package/dist/src/kernel/spec/call.js +167 -0
  191. package/dist/src/kernel/spec/call.js.map +1 -0
  192. package/dist/src/kernel/spec/emitReference.js +9 -13
  193. package/dist/src/kernel/spec/emitReference.js.map +1 -1
  194. package/dist/src/kernel/spec/emitSurface.js +8 -1
  195. package/dist/src/kernel/spec/emitSurface.js.map +1 -1
  196. package/dist/src/kernel/spec/guidance.js +63 -0
  197. package/dist/src/kernel/spec/guidance.js.map +1 -0
  198. package/dist/src/kernel/spec/wireType.js +36 -0
  199. package/dist/src/kernel/spec/wireType.js.map +1 -0
  200. package/package.json +16 -16
  201. package/pragma.conf.ts +294 -177
  202. package/src/capabilities/block.parity.test.ts +1 -1
  203. package/src/capabilities/callRule.test.ts +147 -0
  204. package/src/capabilities/capabilities/capabilities.test.ts +47 -19
  205. package/src/capabilities/capabilities/capabilities.verb.ts +2 -0
  206. package/src/capabilities/capabilities/catalog.ts +60 -55
  207. package/src/capabilities/capabilities/index.ts +2 -0
  208. package/src/capabilities/capabilities/types.ts +16 -19
  209. package/src/capabilities/colophon/colophon.render.ts +9 -5
  210. package/src/capabilities/colophon/colophon.verb.ts +1 -0
  211. package/src/capabilities/config/get.verb.ts +2 -0
  212. package/src/capabilities/config/runField.ts +3 -3
  213. package/src/capabilities/config/set.verb.ts +3 -0
  214. package/src/capabilities/config/show.verb.ts +2 -0
  215. package/src/capabilities/config/unset.verb.ts +2 -0
  216. package/src/capabilities/create/constants.ts +8 -5
  217. package/src/capabilities/create/create.mcp.test.ts +173 -1
  218. package/src/capabilities/create/create.test.ts +4 -2
  219. package/src/capabilities/create/create.verb.ts +45 -3
  220. package/src/capabilities/create/createGrammar.test.ts +41 -5
  221. package/src/capabilities/create/createSurface.generated.ts +22 -0
  222. package/src/capabilities/create/crossCli.subprocess.test.ts +53 -14
  223. package/src/capabilities/create/index.ts +1 -1
  224. package/src/capabilities/create/pickGenerator.ts +1 -0
  225. package/src/capabilities/create/shippedCreate.subprocess.test.ts +28 -7
  226. package/src/capabilities/distribution.test.ts +6 -3
  227. package/src/capabilities/distribution.ts +6 -0
  228. package/src/capabilities/doctor/checks/checkPackageRefs.ts +14 -2
  229. package/src/capabilities/doctor/doctor.test.ts +38 -1
  230. package/src/capabilities/doctor/doctor.verb.ts +2 -0
  231. package/src/capabilities/emptyRecovery.test.ts +5 -0
  232. package/src/capabilities/graph/connect.verb.ts +2 -0
  233. package/src/capabilities/graph/inspect.render.ts +9 -1
  234. package/src/capabilities/graph/inspect.test.ts +73 -0
  235. package/src/capabilities/graph/inspect.verb.ts +2 -0
  236. package/src/capabilities/graph/query.render.test.ts +35 -0
  237. package/src/capabilities/graph/query.render.ts +45 -7
  238. package/src/capabilities/graph/query.shipped.exec.test.ts +44 -0
  239. package/src/capabilities/graph/query.verb.ts +2 -0
  240. package/src/capabilities/graph/queryText.test.ts +55 -1
  241. package/src/capabilities/graph/queryText.ts +47 -0
  242. package/src/capabilities/graph/runConnect.ts +4 -5
  243. package/src/capabilities/graph/runQuery.ts +23 -9
  244. package/src/capabilities/info/info.verb.ts +2 -0
  245. package/src/capabilities/links.shipped.exec.test.ts +398 -0
  246. package/src/capabilities/listBudget.shipped.exec.test.ts +2 -2
  247. package/src/capabilities/listLookup.shipped.exec.test.ts +122 -13
  248. package/src/capabilities/listQuery.shipped.exec.test.ts +39 -16
  249. package/src/capabilities/lookupBudget.shipped.exec.test.ts +208 -0
  250. package/src/capabilities/meta/mcp.verb.ts +2 -0
  251. package/src/capabilities/ontology/ontology.test.ts +24 -0
  252. package/src/capabilities/ontology/verbs.ts +16 -12
  253. package/src/capabilities/prompt/verbs.ts +10 -4
  254. package/src/capabilities/resources/provider.ts +7 -3
  255. package/src/capabilities/resources/resources.test.ts +2 -1
  256. package/src/capabilities/setup/setup.verb.ts +16 -0
  257. package/src/capabilities/shared/calls.ts +20 -0
  258. package/src/capabilities/skill/render.ts +9 -6
  259. package/src/capabilities/skill/verbs.ts +8 -4
  260. package/src/capabilities/sources/collectStatus.ts +6 -1
  261. package/src/capabilities/sources/index.ts +4 -3
  262. package/src/capabilities/sources/reset.render.test.ts +33 -0
  263. package/src/capabilities/sources/reset.render.ts +43 -0
  264. package/src/capabilities/sources/reset.verb.ts +59 -0
  265. package/src/capabilities/sources/runReset.ts +65 -0
  266. package/src/capabilities/sources/runUpdate.ts +12 -11
  267. package/src/capabilities/sources/sources.test.ts +158 -3
  268. package/src/capabilities/sources/status.render.test.ts +63 -1
  269. package/src/capabilities/sources/status.render.ts +25 -8
  270. package/src/capabilities/sources/status.verb.ts +2 -0
  271. package/src/capabilities/sources/types.ts +26 -0
  272. package/src/capabilities/sources/update.verb.ts +3 -0
  273. package/src/capabilities/surface.test.ts +29 -4
  274. package/src/capabilities/token.parity.test.ts +3 -2
  275. package/src/capabilities/tokenGraph.shipped.exec.test.ts +14 -2
  276. package/src/capabilities/upgrade/upgrade.verb.ts +1 -0
  277. package/src/capabilities/variable.parity.test.ts +2 -1
  278. package/src/capabilities/version/version.verb.ts +1 -0
  279. package/src/capabilities/wireContract.test.ts +110 -0
  280. package/src/constants.ts +4 -3
  281. package/src/kernel/completion/shellDrive.test.ts +2 -2
  282. package/src/kernel/copy.test.ts +1 -1
  283. package/src/kernel/error/PragmaError.test.ts +7 -3
  284. package/src/kernel/error/index.ts +1 -1
  285. package/src/kernel/error/recovery.test.ts +52 -18
  286. package/src/kernel/error/recovery.ts +25 -46
  287. package/src/kernel/error/types.ts +1 -1
  288. package/src/kernel/packs/collect.test.ts +79 -0
  289. package/src/kernel/packs/collect.ts +151 -11
  290. package/src/kernel/packs/compile.test.ts +107 -10
  291. package/src/kernel/packs/compile.ts +100 -11
  292. package/src/kernel/packs/filteredEmpty.test.ts +22 -5
  293. package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +5 -6
  294. package/src/kernel/packs/graphqlSource.test.ts +42 -0
  295. package/src/kernel/packs/iri.ts +5 -4
  296. package/src/kernel/packs/listNotice.test.ts +1 -1
  297. package/src/kernel/packs/nounLink.test.ts +385 -0
  298. package/src/kernel/packs/renderPack.ts +137 -57
  299. package/src/kernel/packs/resolveEntity.test.ts +170 -1
  300. package/src/kernel/packs/resolveEntity.ts +281 -101
  301. package/src/kernel/packs/runBodies.ts +133 -31
  302. package/src/kernel/packs/schema.ts +77 -12
  303. package/src/kernel/packs/sparql/buildListQuery.test.ts +78 -1
  304. package/src/kernel/packs/sparql/buildListQuery.ts +106 -16
  305. package/src/kernel/packs/sparql/buildLookupQuery.ts +44 -13
  306. package/src/kernel/packs/sparql/filterValues.test.ts +36 -4
  307. package/src/kernel/packs/sparql/filterValues.ts +50 -31
  308. package/src/kernel/packs/sparql/runSelect.ts +4 -6
  309. package/src/kernel/packs/storyRules.ts +37 -4
  310. package/src/kernel/packs/tierScope.test.ts +120 -6
  311. package/src/kernel/packs/tierScope.ts +5 -7
  312. package/src/kernel/packs/toolDescription.test.ts +59 -74
  313. package/src/kernel/packs/types.ts +93 -11
  314. package/src/kernel/project/cli/buildProgram.ts +4 -0
  315. package/src/kernel/project/cli/dispatch.ts +34 -8
  316. package/src/kernel/project/cli/suggest.test.ts +77 -0
  317. package/src/kernel/project/cli/suggestNames.ts +47 -1
  318. package/src/kernel/project/cli/verbHelp.ts +16 -19
  319. package/src/kernel/project/mcp/buildServer.ts +15 -4
  320. package/src/kernel/project/mcp/envelope.ts +3 -2
  321. package/src/kernel/project/mcp/instructions.ts +123 -35
  322. package/src/kernel/project/mcp/prompts/prompts.test.ts +136 -20
  323. package/src/kernel/project/mcp/registerVerb.test.ts +28 -0
  324. package/src/kernel/project/mcp/registerVerb.ts +67 -29
  325. package/src/kernel/render/__snapshots__/renderers.test.ts.snap +1 -1
  326. package/src/kernel/render/renderers.test.ts +2 -2
  327. package/src/kernel/render/renderers.ts +3 -3
  328. package/src/kernel/render/turtle.ts +24 -4
  329. package/src/kernel/runtime/graphpack/build.ts +58 -1
  330. package/src/kernel/runtime/graphpack/graphpack.test.ts +20 -0
  331. package/src/kernel/runtime/graphpack/manifest.ts +15 -0
  332. package/src/kernel/runtime/graphpack/read.ts +4 -6
  333. package/src/kernel/runtime/graphpack/schemas.ts +1 -0
  334. package/src/kernel/runtime/graphpack/types.ts +13 -0
  335. package/src/kernel/runtime/loadSession.ts +8 -1
  336. package/src/kernel/runtime/packVersion.test.ts +61 -0
  337. package/src/kernel/runtime/packVersion.ts +84 -0
  338. package/src/kernel/runtime/readEntity.ts +61 -6
  339. package/src/kernel/runtime/resolveSources.test.ts +90 -7
  340. package/src/kernel/runtime/resolveSources.ts +91 -10
  341. package/src/kernel/runtime/storeReadiness.ts +4 -4
  342. package/src/kernel/runtime/types.ts +12 -0
  343. package/src/kernel/spec/call.test.ts +95 -0
  344. package/src/kernel/spec/call.ts +186 -0
  345. package/src/kernel/spec/emitReference.ts +9 -13
  346. package/src/kernel/spec/emitSurface.ts +9 -1
  347. package/src/kernel/spec/guidance.test.ts +49 -0
  348. package/src/kernel/spec/guidance.ts +68 -0
  349. package/src/kernel/spec/index.ts +4 -0
  350. package/src/kernel/spec/surfaceConformance.test.ts +2 -2
  351. package/src/kernel/spec/types.ts +64 -7
  352. package/src/kernel/spec/wireType.ts +53 -0
  353. package/src/testing/behavioral/README.md +1 -1
  354. package/src/testing/behavioral/errorMatrix.mcp.test.ts +2 -1
  355. package/src/testing/behavioral/journeys.firstInstall.test.ts +72 -2
  356. package/src/testing/behavioral/parity.test.ts +40 -0
  357. package/src/testing/eval/__snapshots__/eval.test.ts.snap +1 -1
  358. package/src/testing/eval/cases/assembly.ts +4 -3
  359. package/src/testing/eval/cases/stable.ts +2 -3
  360. package/src/testing/helpers/callSchema.ts +40 -0
  361. package/src/testing/helpers/parity.ts +35 -2
  362. package/src/testing/setupCallChecking.ts +30 -0
  363. package/dist/src/capabilities/capabilities/hints.js +0 -223
  364. package/dist/src/capabilities/capabilities/hints.js.map +0 -1
  365. package/src/capabilities/capabilities/hints.ts +0 -266
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The wire contract of list-valued parameters, derived from the registry.
3
+ *
4
+ * Two recorded failures are the reason this file exists. A weak model asked
5
+ * for twenty tokens' variables with twenty `variable_list` calls, because over
6
+ * MCP a filter took ONE value while the CLI took the flag repeated; a stronger
7
+ * one passed `name: "color.text"` to `token_lookup` and was refused by schema
8
+ * validation over a pair of brackets. So: every parameter that takes several
9
+ * values ADVERTISES an array, and accepts one bare value as a list of one.
10
+ *
11
+ * Derived rather than listed — a story declared tomorrow is held to the rule
12
+ * by the act of declaring it.
13
+ */
14
+
15
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
16
+ import { z } from "zod";
17
+ import { buildToolShape } from "../kernel/project/mcp/registerVerb.js";
18
+ import { toolName } from "../kernel/spec/index.js";
19
+ import type { ParamSpec, VerbSpec } from "../kernel/spec/types.js";
20
+ import { type McpHarness, projectMcp } from "../testing/helpers/projectMcp.js";
21
+ import { capabilities } from "./index.js";
22
+
23
+ const exposed: readonly VerbSpec[] = capabilities
24
+ .flatMap((module) => module.verbs)
25
+ .filter((verb) => !verb.hidden && verb.capability.mcp.expose !== false);
26
+
27
+ /** Every `[tool, param]` pair whose param satisfies `test`. */
28
+ function paramsWhere(
29
+ test: (param: ParamSpec) => boolean,
30
+ ): (readonly [string, string, VerbSpec, ParamSpec])[] {
31
+ return exposed.flatMap((verb) =>
32
+ verb.params
33
+ .filter(test)
34
+ .map((param) => [toolName(verb.path), param.name, verb, param] as const),
35
+ );
36
+ }
37
+
38
+ /** One admissible value for a param: its first enum value, else any word. */
39
+ const sample = (param: ParamSpec): string =>
40
+ param.kind === "enum" ? (param.values.at(0) ?? "") : "anything";
41
+
42
+ /** Parse ONE field of a tool's input shape, leaving its other params aside. */
43
+ function parseField(verb: VerbSpec, param: ParamSpec, value: unknown) {
44
+ const field = buildToolShape(verb)[param.name];
45
+ if (!field) throw new Error(`no "${param.name}" in the tool shape`);
46
+ return z.object({ [param.name]: field }).safeParse({ [param.name]: value });
47
+ }
48
+
49
+ const variadic = paramsWhere((param) => param.kind === "string[]");
50
+ const repeatable = paramsWhere(
51
+ (param) => param.kind !== "string[]" && param.repeatable === true,
52
+ );
53
+
54
+ describe("a parameter that takes several values takes one, too", () => {
55
+ it("the registry has both kinds (the derivation is not vacuous)", () => {
56
+ expect(variadic.length).toBeGreaterThan(0);
57
+ expect(repeatable.length).toBeGreaterThan(0);
58
+ });
59
+
60
+ it.each(variadic)(
61
+ "%s { %s }: a bare string is a list of one",
62
+ (_tool, name, verb, param) => {
63
+ expect(parseField(verb, param, "color.text")).toEqual({
64
+ success: true,
65
+ data: { [name]: ["color.text"] },
66
+ });
67
+ expect(parseField(verb, param, ["a", "b"]).success).toBe(true);
68
+ },
69
+ );
70
+
71
+ it.each(repeatable)(
72
+ "%s { %s }: an array and a bare string are both accepted",
73
+ (_tool, name, verb, param) => {
74
+ const value = sample(param);
75
+ expect(parseField(verb, param, [value, value]).success).toBe(true);
76
+ expect(parseField(verb, param, value)).toEqual({
77
+ success: true,
78
+ data: { [name]: [value] },
79
+ });
80
+ },
81
+ );
82
+ });
83
+
84
+ describe("what is advertised is a plain array", () => {
85
+ let harness: McpHarness;
86
+ let schemas: Map<string, Record<string, Record<string, unknown>>>;
87
+ beforeAll(async () => {
88
+ harness = await projectMcp(capabilities);
89
+ schemas = new Map(
90
+ (await harness.listTools()).map((tool) => [
91
+ tool.name,
92
+ ((tool.inputSchema as { properties?: unknown }).properties ??
93
+ {}) as Record<string, Record<string, unknown>>,
94
+ ]),
95
+ );
96
+ });
97
+ afterAll(() => harness.cleanup());
98
+
99
+ // `anyOf` is what a `string | string[]` union would emit, and it is the
100
+ // shape the weaker models read badly — so the coercion must not leak into
101
+ // the advertised schema.
102
+ it.each([...variadic, ...repeatable])(
103
+ "%s { %s } is `type: array`, never `anyOf`",
104
+ (tool, name) => {
105
+ const advertised = schemas.get(tool)?.[name];
106
+ expect(advertised?.type).toBe("array");
107
+ expect(advertised).not.toHaveProperty("anyOf");
108
+ },
109
+ );
110
+ });
package/src/constants.ts CHANGED
@@ -61,9 +61,10 @@ const PROJECT_CONFIG_FILENAME = `${identity.name}.config.ts`;
61
61
  /**
62
62
  * The distribution's name plus a space: the prefix a `recovery.cli` hint carries
63
63
  * so it quotes a command the installed binary answers to (D5). Kernel hints are
64
- * authored through `cliRecovery`, which prepends it; `packs/schema.ts` REJECTS
65
- * it in a user-authored pack's `emptyRecovery.cli`, because the CONSUMING
66
- * distribution's renderer supplies its own. Use {@link BIN_NAME} for prose —
64
+ * authored through `callRecovery`, whose call renderer prepends it; a pack's
65
+ * `emptyRecovery.call` names a verb path and never a binary (`packs/schema.ts`
66
+ * rejects a command line there), because the CONSUMING distribution's renderer
67
+ * supplies its own. Use {@link BIN_NAME} for prose —
67
68
  * this constant's trailing space belongs to the recovery invariant, not to
68
69
  * sentences.
69
70
  */
@@ -339,7 +339,7 @@ const STRUCTURE = [
339
339
  at: "pragma create <TAB>",
340
340
  words: ["pragma", "create", ""],
341
341
  cword: 2,
342
- offers: ["application", "component", "package"],
342
+ offers: ["application", "component", "package", "page"],
343
343
  },
344
344
  {
345
345
  at: "pragma --format <TAB>",
@@ -546,7 +546,7 @@ describe.skipIf(!hasShell("fish"))(
546
546
  },
547
547
  {
548
548
  line: "pragma create ",
549
- offers: ["application", "component", "package"],
549
+ offers: ["application", "component", "package", "page"],
550
550
  },
551
551
  // fish's own inline convention: it returns the whole `--flag=value` word,
552
552
  // not the bare value bash offers. Assert what fish returns.
@@ -438,7 +438,7 @@ describe("capability commands (PROTECTED)", () => {
438
438
  it("no command quoted in capability prose is a bare literal", () => {
439
439
  // The other half of the same promise, and the half the position rule cannot
440
440
  // reach: an empty-state hint, a recovery MESSAGE (the second argument to
441
- // `cliRecovery`, beside a first argument the position rule already covers),
441
+ // `callRecovery`, beside a first argument the position rule already covers),
442
442
  // a `sources status` headline, a wizard step's title. They reach the same
443
443
  // user with the same instruction, and seven of them named this distribution
444
444
  // while the rule above reported zero exemptions.
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import { ISSUES_URL } from "../../constants.js";
3
3
  import { errorEnvelope, successEnvelope } from "../render/envelope.js";
4
4
  import { PragmaError } from "./PragmaError.js";
5
- import { cliRecovery } from "./recovery.js";
5
+ import { callRecovery } from "./recovery.js";
6
6
  import { serializeError } from "./serialize.js";
7
7
 
8
8
  describe("PragmaError factories", () => {
@@ -76,13 +76,17 @@ describe("serializeError", () => {
76
76
  it("includes suggestions, recovery, validOptions, and filters when present", () => {
77
77
  const error = PragmaError.notFound("block", "Buton", {
78
78
  suggestions: ["Button"],
79
- recovery: cliRecovery("block list", "List blocks."),
79
+ recovery: callRecovery({ verb: "block list" }, "List blocks."),
80
80
  });
81
81
  expect(serializeError(error)).toEqual({
82
82
  code: "ENTITY_NOT_FOUND",
83
83
  message: 'block "Buton" not found.',
84
84
  suggestions: ["Button"],
85
- recovery: { cli: "pragma block list", message: "List blocks." },
85
+ recovery: {
86
+ cli: "pragma block list",
87
+ message: "List blocks.",
88
+ mcp: { tool: "block_list", params: {} },
89
+ },
86
90
  });
87
91
  });
88
92
  });
@@ -8,7 +8,7 @@
8
8
 
9
9
  export { ERROR_CODES } from "./constants.js";
10
10
  export { PragmaError } from "./PragmaError.js";
11
- export { cliRecovery } from "./recovery.js";
11
+ export { callRecovery } from "./recovery.js";
12
12
  export {
13
13
  renderErrorJson,
14
14
  renderErrorLlm,
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { RECOVERY_CLI_PREFIX } from "../../constants.js";
3
- import { cliRecovery } from "./recovery.js";
3
+ import { callRecovery } from "./recovery.js";
4
4
 
5
5
  describe("recovery.cli invariant (D5)", () => {
6
6
  it("carries the shipped distribution's recovery prefix", () => {
@@ -11,27 +11,61 @@ describe("recovery.cli invariant (D5)", () => {
11
11
  expect(RECOVERY_CLI_PREFIX).toBe("pragma ");
12
12
  });
13
13
 
14
- it("prepends the distribution's prefix to the command it is given", () => {
15
- // The caller passes the SUFFIX, so a hint naming the wrong binary is
16
- // unwritable rather than merely asserted against. What replaced the deleted
17
- // `assertRecoveryCli` is `kernel/copy.test.ts`'s position rule, which sees
18
- // the raw `cli:` literals that never reached this function at all — the only
19
- // place a wrong prefix was ever actually written.
20
- expect(cliRecovery("config show", "See the resolved config.")).toEqual({
21
- cli: "pragma config show",
22
- message: "See the resolved config.",
14
+ it("derives both spellings from the one call it is given", () => {
15
+ // The caller names a CALL, so a hint naming the wrong binary — or a CLI
16
+ // string and an MCP hint that disagree about an argument — is unwritable
17
+ // rather than merely asserted against. `kernel/copy.test.ts`'s position
18
+ // rule still sees the raw `cli:` literals that never reach this function.
19
+ expect(
20
+ callRecovery(
21
+ { verb: "config unset", params: { key: "tier" } },
22
+ "Clear the field.",
23
+ ),
24
+ ).toEqual({
25
+ cli: "pragma config unset tier",
26
+ message: "Clear the field.",
27
+ // A mutating tool is plan-first: the recovery never carries `confirm`.
28
+ mcp: { tool: "config_unset", params: { key: "tier" } },
23
29
  });
24
30
  });
25
31
 
26
- it("carries an MCP tool alongside the command when one is given", () => {
32
+ it("spells a flag, quotes what a shell would split, and repeats a variadic positional", () => {
27
33
  expect(
28
- cliRecovery("sources update", "Build the store.", {
29
- tool: "sources_update",
30
- }),
31
- ).toEqual({
32
- cli: "pragma sources update",
33
- message: "Build the store.",
34
- mcp: { tool: "sources_update" },
34
+ callRecovery(
35
+ { verb: "token consumers", params: { symbol: "color.text" } },
36
+ "m",
37
+ ).cli,
38
+ ).toBe("pragma token consumers --symbol color.text");
39
+ expect(
40
+ callRecovery(
41
+ { verb: "graph query", params: { sparql: "ASK { ?s ?p 'x' }" } },
42
+ "m",
43
+ ).cli,
44
+ ).toBe("pragma graph query 'ASK { ?s ?p '\\''x'\\'' }'");
45
+ expect(
46
+ callRecovery(
47
+ { verb: "block lookup", params: { name: ["Button", "Card"] } },
48
+ "m",
49
+ ).cli,
50
+ ).toBe("pragma block lookup Button Card");
51
+ expect(
52
+ callRecovery(
53
+ { verb: "sources update", params: { skipInvalid: true } },
54
+ "m",
55
+ ).cli,
56
+ ).toBe("pragma sources update --skip-invalid");
57
+ expect(
58
+ callRecovery(
59
+ { verb: "sources update", params: { skipInvalid: false } },
60
+ "m",
61
+ ).cli,
62
+ ).toBe("pragma sources update");
63
+ });
64
+
65
+ it("names no MCP tool for a verb withheld from MCP", () => {
66
+ expect(callRecovery({ verb: "version" }, "See the version.")).toEqual({
67
+ cli: "pragma version",
68
+ message: "See the version.",
35
69
  });
36
70
  });
37
71
  });
@@ -1,58 +1,37 @@
1
1
  /**
2
- * The recovery-string invariant (D5).
2
+ * The recovery invariant (D5): a `recovery.cli` hint quotes a command the
3
+ * installed binary answers to, so it begins with {@link RECOVERY_CLI_PREFIX}.
3
4
  *
4
- * A `recovery.cli` hint quotes a command the installed binary answers to, so it
5
- * must begin with {@link RECOVERY_CLI_PREFIX} — the distribution's own `name`
6
- * plus a space. {@link cliRecovery} takes the command SUFFIX and prepends the
7
- * prefix itself, so a hint that names the wrong binary is unwritable rather
8
- * than merely detected. That is why there is no assertion here: an assertion
9
- * over a string the caller composed from the prefix cannot fail, and the hints
10
- * that were actually wrong were raw `cli:` object literals that never reached
11
- * this function at all. `kernel/copy.test.ts` covers those, at the position.
12
- *
13
- * A THIRD authoring route is also legal and reached by NEITHER guard: a `cli`
14
- * DERIVED from the program's own name at the call site. One site does this —
15
- * the create mount (`capabilities/create/mount.ts`,
16
- * `[...detail.chain, suggestion].join(" ")`), whose `chain[0]` is the root
17
- * Commander program's name, `BIN_NAME` by wiring. It bypasses
18
- * {@link cliRecovery}, and the position rule is structurally blind to it (it
19
- * flags QUOTED literals containing the distribution's name, never a computed
20
- * expression) — so D5 holds there by derivation, and the derivation is pinned
21
- * where the value surfaces: `createGrammar.test.ts` COMPOSES its expected
22
- * `cli` from {@link RECOVERY_CLI_PREFIX}, so a renamed root program reddens
23
- * the cell naming the constant. (A separate `startsWith` assertion cannot
24
- * pin it — behind an exact pin of the same value it has no reachable
25
- * failing input.)
26
- *
27
- * `kernel/packs/schema.ts` holds a user-authored pack's `emptyRecovery.cli` to
28
- * the same shape from the other side — it must NOT carry a prefix, because the
29
- * consuming distribution's renderer supplies one.
5
+ * {@link callRecovery} takes a CALL and the one call renderer spells it, prefix
6
+ * included, so a hint naming the wrong binary — or a `cli` and an `mcp` that
7
+ * disagree — is unwritable. Two routes do not pass through here:
8
+ * raw `cli:` object literals (`kernel/copy.test.ts` polices those at the
9
+ * position), and the create mount, which DERIVES its `cli` from the root
10
+ * program's name (`capabilities/create/mount.ts`; pinned by
11
+ * `createGrammar.test.ts`, whose expectation is composed from the prefix).
12
+ * A pack's `emptyRecovery.call` is held to the same shape from the other side
13
+ * by `kernel/packs/schema.ts`: a verb path, never a binary name.
30
14
  */
31
15
 
32
- import { RECOVERY_CLI_PREFIX } from "../../constants.js";
16
+ import { callTool, renderCall } from "../spec/call.js";
17
+ import type { Call } from "../spec/types.js";
33
18
  import type { Recovery } from "./types.js";
34
19
 
35
20
  /**
36
- * Build a {@link Recovery} whose `cli` command carries the distribution's own
37
- * prefix, optionally pairing it with an MCP tool an agent can call.
21
+ * Build a {@link Recovery} from the call that recovers.
38
22
  *
39
- * A recovery may need to speak to BOTH surfaces: the `cli` string guides a human,
40
- * while `mcp` names the tool an agent invokes (an agent cannot run a shell
41
- * command). The single human `message` is shared by both.
23
+ * A recovery speaks to BOTH surfaces: `cli` guides a person, while `mcp` names
24
+ * the tool an agent invokes (an agent cannot run a shell command). Both derive
25
+ * from the one call, so they cannot disagree about the verb or its arguments;
26
+ * `mcp` is absent only when the verb is withheld from MCP. Neither spelling
27
+ * ever carries `confirm`: a mutating tool is plan-first, and the plan it
28
+ * returns says how to proceed.
42
29
  *
43
- * @param command - The recovery command WITHOUT the binary name (`sources update`).
30
+ * @param call - The verb to run and the params to run it with.
44
31
  * @param message - Human-readable guidance shown alongside the command.
45
- * @param mcp - The MCP tool (and optional params) an agent calls to recover.
46
- * @returns A recovery hint whose `cli` names this distribution's binary.
32
+ * @returns A recovery hint carrying the call in both spellings.
47
33
  */
48
- export function cliRecovery(
49
- command: string,
50
- message: string,
51
- mcp?: Recovery["mcp"],
52
- ): Recovery {
53
- return {
54
- message,
55
- cli: `${RECOVERY_CLI_PREFIX}${command}`,
56
- ...(mcp ? { mcp } : {}),
57
- };
34
+ export function callRecovery(call: Call, message: string): Recovery {
35
+ const mcp = callTool(call);
36
+ return { message, cli: renderCall(call, "cli"), ...(mcp ? { mcp } : {}) };
58
37
  }
@@ -16,7 +16,7 @@ type ErrorCode = (typeof ERROR_CODES)[number];
16
16
  *
17
17
  * `cli` — when present — is the command as a user would type it: this
18
18
  * distribution's own bin name (`RECOVERY_CLI_PREFIX`) plus a grammar path (D5).
19
- * `cliRecovery` takes the path alone and prepends the prefix, so there is no
19
+ * `callRecovery` takes the path alone and prepends the prefix, so there is no
20
20
  * assertion to make; the one COMPUTED producer (the create mount) derives
21
21
  * the prefix from the program's own name, pinned by a test expectation
22
22
  * COMPOSED from `RECOVERY_CLI_PREFIX` — the routes are enumerated in the
@@ -19,6 +19,7 @@ import type { CapabilityModule, VerbSpec } from "../spec/types.js";
19
19
  import {
20
20
  assembleEffectiveModules,
21
21
  loadEffectiveModules,
22
+ migrateLegacyRecoveries,
22
23
  validateStories,
23
24
  } from "./collect.js";
24
25
  import { assertUniqueVerbs } from "./uniqueness.js";
@@ -210,6 +211,84 @@ describe("validateStories — package stories NEVER throw (PROTECTED)", () => {
210
211
  ]);
211
212
  });
212
213
 
214
+ it("carries a package story's retired emptyRecovery.cli forward instead of losing the noun", () => {
215
+ // A pack built before the grammar changed still has `cli` on disk. The
216
+ // project config gets a hard error for it (its author can rename the key);
217
+ // a package is third-party data, so the hint is migrated when it IS a verb
218
+ // path and otherwise only the hint is dropped — never the noun.
219
+ const withCli = (noun: string, cli: string) => ({
220
+ noun,
221
+ list: {
222
+ ...validPack(noun).list,
223
+ emptyRecovery: { message: "None yet.", cli },
224
+ },
225
+ verbs: [
226
+ {
227
+ ...validPack(noun).list,
228
+ verb: "extras",
229
+ emptyRecovery: { message: "None yet.", cli },
230
+ },
231
+ ],
232
+ });
233
+ const result = validateStories(
234
+ [
235
+ record(
236
+ "pkg/stories/recipe.json",
237
+ JSON.stringify(withCli("recipe", "sources update")),
238
+ ),
239
+ record(
240
+ "pkg/stories/menu.json",
241
+ JSON.stringify(withCli("menu", "acme sources update --all")),
242
+ ),
243
+ ],
244
+ STATIC,
245
+ );
246
+ const [recipe, menu] = result.entries.map((entry) => entry.definition);
247
+ expect(recipe?.list?.emptyRecovery).toEqual({
248
+ message: "None yet.",
249
+ call: { verb: "sources update" },
250
+ });
251
+ expect(recipe?.verbs?.at(0)?.emptyRecovery?.call).toEqual({
252
+ verb: "sources update",
253
+ });
254
+ // Not a verb path: the story survives, the hint does not, and doctor hears.
255
+ expect(menu?.noun).toBe("menu");
256
+ expect(menu?.list?.emptyRecovery).toEqual({ message: "None yet." });
257
+ expect(result.problems.map((problem) => problem.source)).toEqual([
258
+ "pkg/stories/menu.json",
259
+ "pkg/stories/menu.json",
260
+ ]);
261
+ expect(result.problems.at(0)?.message).toMatch(
262
+ /story is kept.*emptyRecovery\.cli.*emptyRecovery\.call/,
263
+ );
264
+ });
265
+
266
+ it("leaves a story with nothing to migrate, and a non-object, untouched", () => {
267
+ const story = validPack("recipe");
268
+ expect(migrateLegacyRecoveries(story)).toEqual({ raw: story, dropped: [] });
269
+ expect(migrateLegacyRecoveries("nope")).toEqual({
270
+ raw: "nope",
271
+ dropped: [],
272
+ });
273
+ // A half that already names a call keeps it; the stale `cli` beside it goes.
274
+ const both = {
275
+ message: "m",
276
+ cli: "doctor",
277
+ call: { verb: "sources update" },
278
+ };
279
+ expect(
280
+ migrateLegacyRecoveries({ noun: "x", verbs: [{ emptyRecovery: both }] }),
281
+ ).toEqual({
282
+ raw: {
283
+ noun: "x",
284
+ verbs: [
285
+ { emptyRecovery: { message: "m", call: { verb: "sources update" } } },
286
+ ],
287
+ },
288
+ dropped: [],
289
+ });
290
+ });
291
+
213
292
  it("last declaration wins for a noun, and the shadowed file is reported", () => {
214
293
  const result = validateStories(
215
294
  [