@canonical/pragma-cli 0.35.0 → 0.37.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 (295) hide show
  1. package/README.md +2 -2
  2. package/bundled-skills/add-standard/SKILL.md +338 -0
  3. package/bundled-skills/adoption-a1-styles/SKILL.md +269 -0
  4. package/bundled-skills/adoption-a2-components/SKILL.md +291 -0
  5. package/bundled-skills/adoption-a3-forms/SKILL.md +260 -0
  6. package/bundled-skills/anatomy-author/ANATOMY_DSL_SPEC.md +406 -0
  7. package/bundled-skills/anatomy-author/SKILL.md +1226 -0
  8. package/bundled-skills/design-auditor/SKILL.md +455 -0
  9. package/bundled-skills/implement-component/SKILL.md +333 -0
  10. package/bundled-skills/specify-component/SKILL.md +331 -0
  11. package/bundled-skills/specify-pattern/SKILL.md +292 -0
  12. package/dist/package.json +24 -20
  13. package/dist/pragma.conf.js +266 -34
  14. package/dist/pragma.conf.js.map +1 -1
  15. package/dist/src/bin.js +1 -1
  16. package/dist/src/bin.js.map +1 -1
  17. package/dist/src/capabilities/capabilities/hints.js +1 -1
  18. package/dist/src/capabilities/capabilities/hints.js.map +1 -1
  19. package/dist/src/capabilities/colophon/colophon.render.js +1 -1
  20. package/dist/src/capabilities/colophon/colophon.render.js.map +1 -1
  21. package/dist/src/capabilities/create/create.verb.js +2 -1
  22. package/dist/src/capabilities/create/create.verb.js.map +1 -1
  23. package/dist/src/capabilities/create/createSurface.generated.js +23 -1
  24. package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
  25. package/dist/src/capabilities/create/mount.js +4 -3
  26. package/dist/src/capabilities/create/mount.js.map +1 -1
  27. package/dist/src/capabilities/doctor/checks/checkNodeVersion.js +11 -6
  28. package/dist/src/capabilities/doctor/checks/checkNodeVersion.js.map +1 -1
  29. package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +60 -4
  30. package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
  31. package/dist/src/capabilities/doctor/checks/checkShellCompletions.js +8 -8
  32. package/dist/src/capabilities/doctor/checks/checkShellCompletions.js.map +1 -1
  33. package/dist/src/capabilities/doctor/checks/harnessInventory.js +195 -0
  34. package/dist/src/capabilities/doctor/checks/harnessInventory.js.map +1 -0
  35. package/dist/src/capabilities/doctor/checks/index.js +6 -6
  36. package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js +38 -0
  37. package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js.map +1 -0
  38. package/dist/src/capabilities/doctor/checks/targetHealth.js +194 -50
  39. package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
  40. package/dist/src/capabilities/doctor/doctor.render.js +43 -64
  41. package/dist/src/capabilities/doctor/doctor.render.js.map +1 -1
  42. package/dist/src/capabilities/doctor/doctor.verb.js +6 -2
  43. package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
  44. package/dist/src/capabilities/doctor/runChecks.js +14 -11
  45. package/dist/src/capabilities/doctor/runChecks.js.map +1 -1
  46. package/dist/src/capabilities/graph/query.render.js +2 -2
  47. package/dist/src/capabilities/graph/query.render.js.map +1 -1
  48. package/dist/src/capabilities/info/collectInfo.js +8 -2
  49. package/dist/src/capabilities/info/collectInfo.js.map +1 -1
  50. package/dist/src/capabilities/info/info.render.js +6 -2
  51. package/dist/src/capabilities/info/info.render.js.map +1 -1
  52. package/dist/src/capabilities/prompt/prompt.render.js +2 -2
  53. package/dist/src/capabilities/prompt/prompt.render.js.map +1 -1
  54. package/dist/src/capabilities/setup/buildPlan.js +43 -39
  55. package/dist/src/capabilities/setup/buildPlan.js.map +1 -1
  56. package/dist/src/capabilities/setup/mode.js +2 -2
  57. package/dist/src/capabilities/setup/operations/index.js +4 -4
  58. package/dist/src/capabilities/setup/operations/index.js.map +1 -1
  59. package/dist/src/capabilities/setup/operations/setupCompletions.js +6 -2
  60. package/dist/src/capabilities/setup/operations/setupCompletions.js.map +1 -1
  61. package/dist/src/capabilities/setup/operations/setupConfig.js +4 -2
  62. package/dist/src/capabilities/setup/operations/setupConfig.js.map +1 -1
  63. package/dist/src/capabilities/setup/operations/setupGenerator.js +156 -58
  64. package/dist/src/capabilities/setup/operations/setupGenerator.js.map +1 -1
  65. package/dist/src/capabilities/setup/operations/setupLsp.js +136 -38
  66. package/dist/src/capabilities/setup/operations/setupLsp.js.map +1 -1
  67. package/dist/src/capabilities/setup/operations/setupMcp.js +101 -52
  68. package/dist/src/capabilities/setup/operations/setupMcp.js.map +1 -1
  69. package/dist/src/capabilities/setup/operations/setupSkills.js +329 -49
  70. package/dist/src/capabilities/setup/operations/setupSkills.js.map +1 -1
  71. package/dist/src/capabilities/setup/plan.js.map +1 -1
  72. package/dist/src/capabilities/setup/plan.render.js +144 -66
  73. package/dist/src/capabilities/setup/plan.render.js.map +1 -1
  74. package/dist/src/capabilities/setup/setup.render.js +1 -1
  75. package/dist/src/capabilities/setup/setup.verb.js +165 -63
  76. package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
  77. package/dist/src/capabilities/setup/targets.js +122 -51
  78. package/dist/src/capabilities/setup/targets.js.map +1 -1
  79. package/dist/src/capabilities/shared/index.js +7 -6
  80. package/dist/src/capabilities/shared/index.js.map +1 -1
  81. package/dist/src/capabilities/shared/packageManager.js +300 -54
  82. package/dist/src/capabilities/shared/packageManager.js.map +1 -1
  83. package/dist/src/capabilities/skill/discover.js +97 -11
  84. package/dist/src/capabilities/skill/discover.js.map +1 -1
  85. package/dist/src/capabilities/skill/render.js +2 -2
  86. package/dist/src/capabilities/skill/render.js.map +1 -1
  87. package/dist/src/capabilities/sources/installSkills.js +145 -3
  88. package/dist/src/capabilities/sources/installSkills.js.map +1 -1
  89. package/dist/src/capabilities/sources/runUpdate.js +68 -2
  90. package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
  91. package/dist/src/capabilities/sources/update.verb.js +3 -3
  92. package/dist/src/capabilities/sources/update.verb.js.map +1 -1
  93. package/dist/src/capabilities/upgrade/runUpgrade.js +43 -7
  94. package/dist/src/capabilities/upgrade/runUpgrade.js.map +1 -1
  95. package/dist/src/capabilities/upgrade/upgrade.render.js +10 -2
  96. package/dist/src/capabilities/upgrade/upgrade.render.js.map +1 -1
  97. package/dist/src/constants.js +13 -2
  98. package/dist/src/constants.js.map +1 -1
  99. package/dist/src/kernel/index.js +11 -2
  100. package/dist/src/kernel/index.js.map +1 -1
  101. package/dist/src/kernel/interactivity.js +68 -0
  102. package/dist/src/kernel/interactivity.js.map +1 -0
  103. package/dist/src/kernel/packs/renderPack.js +3 -3
  104. package/dist/src/kernel/packs/renderPack.js.map +1 -1
  105. package/dist/src/kernel/packs/resolveEntity.js +63 -12
  106. package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
  107. package/dist/src/kernel/packs/runBodies.js +57 -4
  108. package/dist/src/kernel/packs/runBodies.js.map +1 -1
  109. package/dist/src/kernel/packs/schema.js +54 -2
  110. package/dist/src/kernel/packs/schema.js.map +1 -1
  111. package/dist/src/kernel/packs/sparql/applyFilters.js +104 -5
  112. package/dist/src/kernel/packs/sparql/applyFilters.js.map +1 -1
  113. package/dist/src/kernel/packs/sparql/buildLookupQuery.js +310 -43
  114. package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
  115. package/dist/src/kernel/packs/types.js.map +1 -1
  116. package/dist/src/kernel/project/cli/buildProgram.js +1 -1
  117. package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
  118. package/dist/src/kernel/project/cli/dispatch.js +46 -24
  119. package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
  120. package/dist/src/kernel/project/cli/globalFlags.js +4 -1
  121. package/dist/src/kernel/project/cli/globalFlags.js.map +1 -1
  122. package/dist/src/kernel/project/cli/helpFormat.js +1 -2
  123. package/dist/src/kernel/project/cli/helpFormat.js.map +1 -1
  124. package/dist/src/kernel/project/cli/rootHelp.js +42 -9
  125. package/dist/src/kernel/project/cli/rootHelp.js.map +1 -1
  126. package/dist/src/kernel/project/mcp/registerVerb.js +16 -1
  127. package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
  128. package/dist/src/kernel/render/renderers.js +1 -1
  129. package/dist/src/kernel/render/style.js +29 -9
  130. package/dist/src/kernel/render/style.js.map +1 -1
  131. package/dist/src/kernel/render/vocabulary.js +174 -0
  132. package/dist/src/kernel/render/vocabulary.js.map +1 -0
  133. package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js +2 -3
  134. package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js.map +1 -1
  135. package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js +1 -1
  136. package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js.map +1 -1
  137. package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js +4 -0
  138. package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js.map +1 -0
  139. package/dist/src/kernel/runtime/graphpack/embedded.js +13 -6
  140. package/dist/src/kernel/runtime/graphpack/embedded.js.map +1 -1
  141. package/dist/src/kernel/runtime/graphpack/read.js +14 -9
  142. package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
  143. package/dist/src/kernel/runtime/loadSession.js +3 -1
  144. package/dist/src/kernel/runtime/loadSession.js.map +1 -1
  145. package/dist/src/kernel/runtime/probe.js +1 -1
  146. package/dist/src/kernel/runtime/probe.js.map +1 -1
  147. package/dist/src/kernel/runtime/refs/parseRef.js +17 -1
  148. package/dist/src/kernel/runtime/refs/parseRef.js.map +1 -1
  149. package/dist/src/kernel/runtime/refs/resolve.js +9 -3
  150. package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
  151. package/dist/src/kernel/spec/emitReference.js +1 -1
  152. package/dist/src/kernel/spec/emitReference.js.map +1 -1
  153. package/package.json +24 -20
  154. package/pragma.conf.ts +272 -34
  155. package/src/bin.ts +8 -1
  156. package/src/capabilities/block.parity.test.ts +25 -11
  157. package/src/capabilities/block.shipped.exec.test.ts +282 -0
  158. package/src/capabilities/block.tierRank.exec.test.ts +300 -0
  159. package/src/capabilities/capabilities/hints.ts +1 -1
  160. package/src/capabilities/colophon/colophon.render.ts +1 -2
  161. package/src/capabilities/colophon/colophon.test.ts +2 -2
  162. package/src/capabilities/config/collectConfigShow.test.ts +1 -0
  163. package/src/capabilities/create/byteEquality.test.ts +28 -1
  164. package/src/capabilities/create/create.test.ts +1 -0
  165. package/src/capabilities/create/create.verb.ts +2 -1
  166. package/src/capabilities/create/createGrammar.test.ts +5 -2
  167. package/src/capabilities/create/createSurface.generated.ts +23 -1
  168. package/src/capabilities/create/crossCli.subprocess.test.ts +10 -3
  169. package/src/capabilities/create/mount.ts +3 -3
  170. package/src/capabilities/distribution.parity.test.ts +4 -0
  171. package/src/capabilities/doctor/checks/checkNodeVersion.test.ts +49 -0
  172. package/src/capabilities/doctor/checks/checkNodeVersion.ts +11 -7
  173. package/src/capabilities/doctor/checks/checkPackageRefs.ts +69 -4
  174. package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +6 -4
  175. package/src/capabilities/doctor/checks/checkShellCompletions.ts +8 -8
  176. package/src/capabilities/doctor/checks/harnessInventory.test.ts +219 -0
  177. package/src/capabilities/doctor/checks/harnessInventory.ts +298 -0
  178. package/src/capabilities/doctor/checks/index.ts +6 -6
  179. package/src/capabilities/doctor/checks/isSupportedNodeVersion.test.ts +111 -0
  180. package/src/capabilities/doctor/checks/isSupportedNodeVersion.ts +34 -0
  181. package/src/capabilities/doctor/checks/mcpCommand.test.ts +7 -1
  182. package/src/capabilities/doctor/checks/targetHealth.ts +229 -59
  183. package/src/capabilities/doctor/doctor.render.test.ts +108 -32
  184. package/src/capabilities/doctor/doctor.render.ts +56 -80
  185. package/src/capabilities/doctor/doctor.test.ts +247 -35
  186. package/src/capabilities/doctor/doctor.verb.ts +7 -2
  187. package/src/capabilities/doctor/runChecks.ts +14 -11
  188. package/src/capabilities/doctor/types.ts +15 -24
  189. package/src/capabilities/emptyRecovery.test.ts +10 -2
  190. package/src/capabilities/graph/query.render.ts +2 -2
  191. package/src/capabilities/info/collectInfo.ts +8 -1
  192. package/src/capabilities/info/info.render.ts +6 -2
  193. package/src/capabilities/info/info.test.ts +37 -1
  194. package/src/capabilities/info/types.ts +10 -2
  195. package/src/capabilities/lazy.test.ts +26 -2
  196. package/src/capabilities/listLookup.shipped.exec.test.ts +340 -0
  197. package/src/capabilities/prompt/prompt.render.ts +2 -2
  198. package/src/capabilities/renderVocabularySync.test.ts +82 -0
  199. package/src/capabilities/resources/resources.test.ts +38 -2
  200. package/src/capabilities/scopeTypeSync.test.ts +29 -15
  201. package/src/capabilities/setup/buildPlan.ts +45 -41
  202. package/src/capabilities/setup/index.ts +1 -1
  203. package/src/capabilities/setup/mode.ts +2 -2
  204. package/src/capabilities/setup/operations/index.ts +6 -1
  205. package/src/capabilities/setup/operations/setupCompletions.ts +9 -2
  206. package/src/capabilities/setup/operations/setupConfig.ts +7 -2
  207. package/src/capabilities/setup/operations/setupGenerator.ts +227 -84
  208. package/src/capabilities/setup/operations/setupLsp.ts +203 -38
  209. package/src/capabilities/setup/operations/setupMcp.ts +139 -62
  210. package/src/capabilities/setup/operations/setupSkills.ts +399 -60
  211. package/src/capabilities/setup/plan.render.ts +171 -76
  212. package/src/capabilities/setup/plan.ts +17 -12
  213. package/src/capabilities/setup/setup.mcp.correctness.test.ts +9 -9
  214. package/src/capabilities/setup/setup.render.test.ts +50 -36
  215. package/src/capabilities/setup/setup.render.ts +1 -1
  216. package/src/capabilities/setup/setup.test.ts +1126 -50
  217. package/src/capabilities/setup/setup.verb.ts +174 -68
  218. package/src/capabilities/setup/targets.ts +138 -60
  219. package/src/capabilities/setup/types.ts +10 -18
  220. package/src/capabilities/shared/index.ts +18 -6
  221. package/src/capabilities/shared/packageManager.test.ts +421 -6
  222. package/src/capabilities/shared/packageManager.ts +394 -59
  223. package/src/capabilities/skill/bundledSkills.test.ts +347 -0
  224. package/src/capabilities/skill/discover.ts +100 -11
  225. package/src/capabilities/skill/render.ts +2 -2
  226. package/src/capabilities/skill/skill.test.ts +17 -4
  227. package/src/capabilities/sources/installSkills.ts +181 -3
  228. package/src/capabilities/sources/runUpdate.ts +78 -2
  229. package/src/capabilities/sources/sources.test.ts +228 -0
  230. package/src/capabilities/sources/update.verb.ts +3 -3
  231. package/src/capabilities/surface.test.ts +14 -6
  232. package/src/capabilities/upgrade/runUpgrade.ts +45 -6
  233. package/src/capabilities/upgrade/types.ts +10 -2
  234. package/src/capabilities/upgrade/upgrade.render.ts +9 -2
  235. package/src/capabilities/upgrade/upgrade.test.ts +72 -0
  236. package/src/constants.ts +14 -1
  237. package/src/identity.test.ts +18 -5
  238. package/src/kernel/completion/entitySource.test.ts +15 -2
  239. package/src/kernel/completion/safety.test.ts +16 -9
  240. package/src/kernel/config/defaults.test.ts +19 -3
  241. package/src/kernel/config/readConfig.test.ts +1 -1
  242. package/src/kernel/index.ts +11 -2
  243. package/src/kernel/interactivity.test.ts +76 -0
  244. package/src/kernel/interactivity.ts +69 -0
  245. package/src/kernel/packs/compile.test.ts +92 -0
  246. package/src/kernel/packs/renderPack.ts +3 -3
  247. package/src/kernel/packs/resolveEntity.test.ts +75 -14
  248. package/src/kernel/packs/resolveEntity.ts +88 -24
  249. package/src/kernel/packs/runBodies.ts +84 -19
  250. package/src/kernel/packs/schema.ts +60 -4
  251. package/src/kernel/packs/sparql/applyFilters.ts +125 -4
  252. package/src/kernel/packs/sparql/buildLookupQuery.test.ts +290 -0
  253. package/src/kernel/packs/sparql/buildLookupQuery.ts +327 -45
  254. package/src/kernel/packs/toolDescription.test.ts +35 -1
  255. package/src/kernel/packs/types.ts +125 -2
  256. package/src/kernel/project/cli/buildProgram.test.ts +73 -2
  257. package/src/kernel/project/cli/buildProgram.ts +8 -1
  258. package/src/kernel/project/cli/dispatch.test.ts +5 -4
  259. package/src/kernel/project/cli/dispatch.ts +48 -25
  260. package/src/kernel/project/cli/globalFlags.ts +4 -1
  261. package/src/kernel/project/cli/helpFormat.ts +1 -2
  262. package/src/kernel/project/cli/rootHelp.ts +44 -8
  263. package/src/kernel/project/mcp/registerVerb.ts +20 -1
  264. package/src/kernel/render/prefixes.test.ts +2 -0
  265. package/src/kernel/render/renderers.ts +1 -1
  266. package/src/kernel/render/style.ts +32 -9
  267. package/src/kernel/render/vocabulary.ts +276 -0
  268. package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +2 -3
  269. package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +1 -1
  270. package/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.ts +3 -0
  271. package/src/kernel/runtime/graphpack/embedded.ts +14 -6
  272. package/src/kernel/runtime/graphpack/graphpack.test.ts +31 -5
  273. package/src/kernel/runtime/graphpack/read.ts +14 -12
  274. package/src/kernel/runtime/loadSession.ts +3 -1
  275. package/src/kernel/runtime/probe.ts +1 -1
  276. package/src/kernel/runtime/refs/parseRef.test.ts +49 -1
  277. package/src/kernel/runtime/refs/parseRef.ts +25 -1
  278. package/src/kernel/runtime/refs/resolve.ts +9 -3
  279. package/src/kernel/runtime/types.ts +17 -0
  280. package/src/kernel/spec/emitReference.ts +1 -1
  281. package/src/kernel/spec/types.ts +35 -6
  282. package/src/testing/PARITY_GAPS.ts +9 -3
  283. package/src/testing/behavioral/docExamples.test.ts +4 -2
  284. package/src/testing/behavioral/errorMatrix.mcp.test.ts +110 -7
  285. package/src/testing/behavioral/journeys.firstInstall.test.ts +7 -2
  286. package/src/testing/behavioral/journeys.packageStories.test.ts +6 -3
  287. package/src/testing/eval/__snapshots__/eval.test.ts.snap +26 -1
  288. package/src/testing/eval/cases/readNouns.ts +245 -9
  289. package/src/testing/fixtures/blockGraph.ts +28 -13
  290. package/src/testing/fixtures/graph/canonical.ts +95 -12
  291. package/src/testing/helpers/runCli.test.ts +44 -0
  292. package/src/testing/helpers/runCli.ts +27 -3
  293. package/dist/src/capabilities/shared/bands.js +0 -16
  294. package/dist/src/capabilities/shared/bands.js.map +0 -1
  295. package/src/capabilities/shared/bands.ts +0 -16
@@ -1,13 +1,16 @@
1
1
  /**
2
- * The `doctor` run body: the unbanded environment checks plus the banded rows
2
+ * The `doctor` run body: the unscoped environment checks plus the scoped rows
3
3
  * the setup target table derives.
4
4
  *
5
5
  * Two kinds of finding live in one report and they are not the same kind. The
6
6
  * ENVIRONMENT checks — the Node version, this CLI's own version, pack refs, the
7
- * store — diagnose things `setup` cannot install; they carry no band and stay
8
- * their own section. The BANDED rows are exactly the setup targets, in both
9
- * bands, named with the target ids verbatim and repaired by the target's own
10
- * command. Adding a target adds its rows here for free.
7
+ * store — diagnose things `setup` cannot install; they carry no scope and stay
8
+ * their own section. The SCOPED rows are the setup targets, in both scopes,
9
+ * named with the target ids verbatim and repaired by the target's own command
10
+ * — plus, per scope, the `harnesses` inventory row: a listing of what this
11
+ * machine holds and where pragma stands in it, which is the thing the targets
12
+ * are measured against rather than a target itself. Adding a target adds its
13
+ * rows here for free.
11
14
  *
12
15
  * Checks are started eagerly (they run concurrently) and collected in
13
16
  * declaration order for a deterministic report. Each is guarded so a thrown
@@ -22,11 +25,11 @@ import { checkKeStore } from "./checks/checkKeStore.js";
22
25
  import { checkNodeVersion } from "./checks/checkNodeVersion.js";
23
26
  import { checkPackageRefs } from "./checks/checkPackageRefs.js";
24
27
  import { checkPragmaVersion } from "./checks/checkPragmaVersion.js";
25
- import { bandedChecks } from "./checks/targetHealth.js";
28
+ import { scopedChecks } from "./checks/targetHealth.js";
26
29
  import type { CheckResult, DoctorData } from "./types.js";
27
30
 
28
31
  /**
29
- * The unbanded environment checks, each paired with the display name used if it
32
+ * The unscoped environment checks, each paired with the display name used if it
30
33
  * rejects. The fallback name matches the `name` each check returns on success,
31
34
  * so a thrown check reports the same label and stays correlatable.
32
35
  */
@@ -67,16 +70,16 @@ async function guarded(
67
70
  * @note Impure — the checks read the fs, boot the store, and detect harnesses.
68
71
  */
69
72
  export async function runChecks(rt: PragmaRuntime): Promise<DoctorData> {
70
- // The banded rows come back as a batch (one detection pass over the table),
73
+ // The scoped rows come back as a batch (one detection pass over the table),
71
74
  // so they are guarded as a batch: a detection that throws becomes one
72
75
  // attributable failure instead of taking the environment section with it.
73
- const [environmentResults, bandedResults] = await Promise.all([
76
+ const [environmentResults, scopedResults] = await Promise.all([
74
77
  Promise.all(
75
78
  buildEnvironmentChecks(rt).map(([name, promise]) =>
76
79
  guarded(name, promise),
77
80
  ),
78
81
  ),
79
- bandedChecks(rt, BIN_NAME).catch((error: unknown): CheckResult[] => [
82
+ scopedChecks(rt, BIN_NAME).catch((error: unknown): CheckResult[] => [
80
83
  {
81
84
  name: "setup targets",
82
85
  status: "fail",
@@ -88,7 +91,7 @@ export async function runChecks(rt: PragmaRuntime): Promise<DoctorData> {
88
91
  ]),
89
92
  ]);
90
93
 
91
- const checks: CheckResult[] = [...environmentResults, ...bandedResults];
94
+ const checks: CheckResult[] = [...environmentResults, ...scopedResults];
92
95
  return {
93
96
  checks,
94
97
  passed: checks.filter((c) => c.status === "pass").length,
@@ -2,26 +2,17 @@
2
2
  * Data shapes for `pragma doctor` (ported verbatim from the old shell).
3
3
  */
4
4
 
5
- /**
6
- * One of the two config bands a check can concern. Mirrors the harnesses
7
- * `ScopeBand` structurally but is redeclared here so this statically-reachable
8
- * type module never pulls the harnesses runtime into the fast-path module graph.
9
- */
10
- export type ScopeBand = "project" | "global";
5
+ // The scope and status types are part of the rendering vocabulary — the one
6
+ // module that owns both the states and the words (and glyphs) for them.
7
+ // Re-exported here so doctor's type surface stays complete; the definitions,
8
+ // the `available` tier's rationale, and the structural pin against
9
+ // `@canonical/harnesses` live with the vocabulary.
10
+ import type { CheckStatus, Scope } from "../../kernel/render/vocabulary.js";
11
11
 
12
- /**
13
- * Status of a doctor check or one of its sub-items.
14
- *
15
- * `available` is the tier between fail and skip that keeps the report honest:
16
- * an opt-in integration (MCP registration, skills symlinks, a completion
17
- * script) that is detected and installable but that the user has not set up.
18
- * Nothing is broken — a fresh install is HEALTHY with several availables — so
19
- * reporting these as `fail` would teach users that the failure count is noise.
20
- * `fail` stays reserved for a real fault: something set up that no longer
21
- * works, or an environment the CLI cannot run correctly in. `skip` remains
22
- * "nothing to check here" (no shell detected, no harnesses present).
23
- */
24
- export type CheckStatus = "pass" | "fail" | "available" | "skip";
12
+ export type {
13
+ CheckStatus,
14
+ Scope,
15
+ } from "../../kernel/render/vocabulary.js";
25
16
 
26
17
  /**
27
18
  * A structured sub-item under a check — e.g. one resolved package under
@@ -52,13 +43,13 @@ export interface CheckResult {
52
43
  */
53
44
  readonly remedy?: string;
54
45
  /**
55
- * Which config band the check concerns, if any: `global` for the user/home
46
+ * Which config scope the check concerns, if any: `global` for the user/home
56
47
  * level (shell completions), `project` for per-repo config (skills). The MCP
57
- * checks derive their band from the harnesses they found. The renderer groups
58
- * banded checks into Global/Project sections; environment checks (Node,
59
- * versions, store) carry no band.
48
+ * checks derive their scope from the harnesses they found. The renderer groups
49
+ * scoped checks into Global/Project sections; environment checks (Node,
50
+ * versions, store) carry no scope.
60
51
  */
61
- readonly band?: ScopeBand;
52
+ readonly scope?: Scope;
62
53
  }
63
54
 
64
55
  /** Aggregated results from all doctor checks — one count per status tier. */
@@ -35,6 +35,9 @@ function storyFor(noun: string): PackDefinition {
35
35
  const PREFIXES = {
36
36
  ds: "https://ds.canonical.com/",
37
37
  cs: "https://ds.canonical.com/code-standards/",
38
+ // The `standard` list query names `skos:broader` for its category roll-up —
39
+ // a CORE prefix on the real build path, which this in-memory helper bypasses.
40
+ skos: "http://www.w3.org/2004/02/skos/core#",
38
41
  owl: "http://www.w3.org/2002/07/owl#",
39
42
  rdfs: "http://www.w3.org/2000/01/rdf-schema#",
40
43
  xsd: "http://www.w3.org/2001/XMLSchema#",
@@ -85,7 +88,12 @@ const listVerb = (pack: PackDefinition): VerbSpec =>
85
88
  const PACK_LISTS: readonly { pack: PackDefinition; hint: RegExp }[] = [
86
89
  { pack: storyFor("modifier"), hint: /pragma sources update/ },
87
90
  { pack: storyFor("token"), hint: /pragma sources update/ },
88
- { pack: storyFor("standard"), hint: /broaden the filter/ },
91
+ // CHANGED DELIBERATELY. `standard` used to fall through to the generic
92
+ // build/broaden hint, and the build half of it is actively WRONG for this
93
+ // noun: the code standards ride the embedded snapshot and answer with no
94
+ // `sources update` at all. It now authors its own, pointing at the one
95
+ // surface that reads the category vocabulary out of the graph.
96
+ { pack: storyFor("standard"), hint: /pragma standard categories/ },
89
97
  ];
90
98
 
91
99
  const REAL = { dryRun: false, undo: false, yes: false };
@@ -108,7 +116,7 @@ describe("pack list empty-state (U5, PROTECTED)", () => {
108
116
  const { formatters } = listVerb(pack).output;
109
117
  // The message + runnable hint live on the empty-state seam — the
110
118
  // dispatcher routes them to stderr, keeping plain stdout pure data.
111
- const notice = formatters.emptyNotice?.([]);
119
+ const notice = formatters.notice?.([]);
112
120
  expect(notice).toContain(`No ${pack.noun} entries found.`);
113
121
  expect(notice).toMatch(hint);
114
122
  // JSON is the uniform empty array — unchanged by the message.
@@ -37,9 +37,9 @@ function formatTriples(
37
37
 
38
38
  export const queryFormatters: Formatters<QueryResult> = {
39
39
  // Zero rows/triples: plain stdout stays empty — the notice is
40
- // `emptyNotice`, routed to stderr (exit 0) by the dispatcher so a pipe
40
+ // `notice`, routed to stderr (exit 0) by the dispatcher so a pipe
41
41
  // reads no prose. ASK always has a result and never goes empty.
42
- emptyNotice(result) {
42
+ notice(result) {
43
43
  if (result.type === "select" && result.bindings.length === 0) {
44
44
  return "No results.";
45
45
  }
@@ -26,6 +26,7 @@ import {
26
26
  detectInstallSource,
27
27
  PRAGMA_PACKAGE,
28
28
  pmUpdateCommand,
29
+ updateGuidance,
29
30
  } from "../shared/index.js";
30
31
  import type { InfoData, InfoUpdate } from "./types.js";
31
32
 
@@ -44,12 +45,17 @@ export async function collectInfo(runtime: PragmaRuntime): Promise<InfoData> {
44
45
 
45
46
  // Update-check: unconditional (no flag exists), 3s timeout, silent-fail.
46
47
  const registry = await checkRegistryVersion(PRAGMA_PACKAGE, config.channel);
48
+ // Only a GLOBAL install gets a command; every other state gets the honest
49
+ // guidance sentence — a confidently wrong `npm i -g` against a linked
50
+ // checkout would overwrite the development link.
47
51
  const update: InfoUpdate | undefined =
48
52
  registry && registry.latest !== runtime.version
49
53
  ? {
50
54
  current: runtime.version,
51
55
  latest: registry.latest,
52
- command: pmUpdateCommand(install.pm, PRAGMA_PACKAGE),
56
+ ...(install.kind === "global"
57
+ ? { command: pmUpdateCommand(install, PRAGMA_PACKAGE) }
58
+ : { guidance: updateGuidance(install) }),
53
59
  }
54
60
  : undefined;
55
61
  const updateSkipped = registry === undefined;
@@ -62,6 +68,7 @@ export async function collectInfo(runtime: PragmaRuntime): Promise<InfoData> {
62
68
  return {
63
69
  version: runtime.version,
64
70
  installSource: install.label,
71
+ installKind: install.kind,
65
72
  ...(update ? { update } : {}),
66
73
  updateSkipped,
67
74
  ...(entities !== undefined ? { entities } : {}),
@@ -37,7 +37,9 @@ export const infoFormatters: Formatters<InfoData> = {
37
37
  lines.push(
38
38
  "",
39
39
  `Update available: ${data.update.current} → ${data.update.latest}`,
40
- ` Run: ${data.update.command}`,
40
+ data.update.command
41
+ ? ` Run: ${data.update.command}`
42
+ : ` ${data.update.guidance}`,
41
43
  );
42
44
  }
43
45
  return lines.join("\n");
@@ -61,7 +63,9 @@ export const infoFormatters: Formatters<InfoData> = {
61
63
  }
62
64
  if (data.update) {
63
65
  lines.push(
64
- `- Update available: ${data.update.current} → ${data.update.latest} (\`${data.update.command}\`)`,
66
+ data.update.command
67
+ ? `- Update available: ${data.update.current} → ${data.update.latest} (\`${data.update.command}\`)`
68
+ : `- Update available: ${data.update.current} → ${data.update.latest} — ${data.update.guidance}`,
65
69
  );
66
70
  }
67
71
  return lines.join("\n");
@@ -17,9 +17,26 @@ import { bootRuntime } from "../../kernel/runtime/boot.js";
17
17
  import type { GlobalFlags, PragmaRuntime } from "../../kernel/runtime/types.js";
18
18
  import type { VerbSpec } from "../../kernel/spec/types.js";
19
19
  import { projectMcp } from "../../testing/helpers/projectMcp.js";
20
+ import type { InstallSource } from "../shared/index.js";
20
21
  import { infoModule } from "./index.js";
21
22
  import type { InfoData } from "./types.js";
22
23
 
24
+ // Pin the install-source detection: the real detector reads THIS process
25
+ // (whose entry is a source checkout — an honest `unknown`), and these tests
26
+ // are about the enrichment around it, not the detection itself (covered by
27
+ // `shared/packageManager.test.ts`). The holder lets a case retarget it.
28
+ const detection = vi.hoisted(() => ({ install: undefined as unknown }));
29
+ vi.mock("../shared/index.js", async (importOriginal) => ({
30
+ ...(await importOriginal<object>()),
31
+ detectInstallSource: () => detection.install,
32
+ }));
33
+
34
+ const GLOBAL_NPM: InstallSource = {
35
+ kind: "global",
36
+ pm: "npm",
37
+ label: "npm (global)",
38
+ };
39
+
23
40
  const infoVerb = infoModule.verbs[0] as VerbSpec;
24
41
  const FLAGS_JSON: GlobalFlags = {
25
42
  llm: false,
@@ -54,6 +71,7 @@ let prevXdg: string | undefined;
54
71
  beforeEach(() => {
55
72
  prevXdg = process.env.XDG_CONFIG_HOME;
56
73
  process.env.XDG_CONFIG_HOME = tmpCwd();
74
+ detection.install = GLOBAL_NPM;
57
75
  });
58
76
  afterEach(() => {
59
77
  process.env.XDG_CONFIG_HOME = prevXdg;
@@ -74,12 +92,30 @@ describe("info — update-check enrichment", () => {
74
92
  const data = await collect(rt);
75
93
 
76
94
  expect(data.update).toMatchObject({ current: VERSION, latest: "99.0.0" });
77
- expect(data.update?.command).toContain("@canonical/pragma-cli");
95
+ expect(data.update?.command).toBe("npm i -g @canonical/pragma-cli");
96
+ expect(data.installSource).toBe("npm (global)");
97
+ expect(data.installKind).toBe("global");
78
98
  expect(data.updateSkipped).toBe(false);
79
99
  // The storeless invariant: the enrichment must NOT boot the store.
80
100
  expect(rt.store.booted).toBe(false);
81
101
  });
82
102
 
103
+ it("a LINKED install gets guidance, never a command (would clobber the link)", async () => {
104
+ detection.install = {
105
+ kind: "linked",
106
+ pm: "npm",
107
+ target: "/home/u/code/pragma/packages/cli/pragma",
108
+ label: "npm link (development checkout)",
109
+ } satisfies InstallSource;
110
+ stubRegistry("99.0.0");
111
+ const data = await collect(bootRuntime(FLAGS_JSON, tmpCwd()));
112
+
113
+ expect(data.installKind).toBe("linked");
114
+ expect(data.installSource).toBe("npm link (development checkout)");
115
+ expect(data.update?.command).toBeUndefined();
116
+ expect(data.update?.guidance).toMatch(/development checkout/i);
117
+ });
118
+
83
119
  it("marks `updateSkipped` when the registry is unreachable", async () => {
84
120
  stubRegistry("offline");
85
121
  const data = await collect(bootRuntime(FLAGS_JSON, tmpCwd()));
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import type { ConfigOrigins } from "../../kernel/config/types.js";
6
+ import type { InstallKind } from "../../kernel/render/vocabulary.js";
6
7
 
7
8
  /** The config summary `info` reports — resolved values plus provenance. */
8
9
  export interface InfoConfig {
@@ -20,8 +21,12 @@ export interface InfoConfig {
20
21
  export interface InfoUpdate {
21
22
  readonly current: string;
22
23
  readonly latest: string;
23
- /** The package-manager command that would apply the update. */
24
- readonly command: string;
24
+ /** The package-manager command that would apply the update — only for a
25
+ * GLOBAL install; every other state carries {@link guidance} instead. */
26
+ readonly command?: string;
27
+ /** The honest sentence for an install with no sanctioned update command
28
+ * (linked / ephemeral / workspace / unknown). */
29
+ readonly guidance?: string;
25
30
  }
26
31
 
27
32
  /**
@@ -31,7 +36,10 @@ export interface InfoUpdate {
31
36
  */
32
37
  export interface InfoData {
33
38
  readonly version: string;
39
+ /** The install-source display label (e.g. `npm (global)`). */
34
40
  readonly installSource: string;
41
+ /** The install-source state the label renders. */
42
+ readonly installKind: InstallKind;
35
43
  /** Set when a newer CLI release is available on the active channel. */
36
44
  readonly update?: InfoUpdate;
37
45
  /** True when the registry could not be reached (the update-check was skipped). */
@@ -88,8 +88,9 @@ describe("lazy dispatch — module-graph probe (PROTECTED)", () => {
88
88
 
89
89
  it("the dispatch path never reaches the embedded n-quads module (PROTECTED)", () => {
90
90
  // `activeStories` reads the pack's carried stories from their OWN generated
91
- // module rather than through `graphpack/embedded.ts`, which statically
92
- // imports the ~1.9 MB `pack.generated.ts`. Restoring that edge costs a
91
+ // module rather than through `graphpack/embedded.ts`, which reaches the
92
+ // ~2.1 MB `pack.generated.ts` (dynamically since the manifest split, but
93
+ // this path must not reach it at all). Restoring that edge costs a
93
94
  // measured +23 ms on EVERY dispatched command, and the whole test suite
94
95
  // passes with it restored — the split is prose in three docblocks and
95
96
  // nothing else. This is the constraint those docblocks describe.
@@ -104,6 +105,29 @@ describe("lazy dispatch — module-graph probe (PROTECTED)", () => {
104
105
  }
105
106
  });
106
107
 
108
+ it("`embedded.ts` itself never statically imports the payload (PROTECTED)", () => {
109
+ // The store-boot path DOES go through `graphpack/embedded.ts`, so the test
110
+ // above cannot cover it. `materializeEmbeddedPack` reads the manifest to
111
+ // name the cache directory and then returns early when the pack is already
112
+ // there — the common case — so a static import of `pack.generated.ts` would
113
+ // parse ~2.1 MB of n-quads to reach that return, on every boot.
114
+ //
115
+ // Restoring `import { dataNq } from "./embedded/pack.generated.js"` at
116
+ // module scope costs a measured ~370 ms per CLI invocation on a
117
+ // 30,340-triple pack, and every other test still passes. This is the only
118
+ // thing standing between that edit and a silent regression.
119
+ for (const entry of [
120
+ "../kernel/runtime/graphpack/embedded.ts",
121
+ "../kernel/runtime/loadSession.ts",
122
+ ]) {
123
+ const graph = staticImportGraph(resolve(here, entry));
124
+ expect(has(graph, "embedded/pack.manifest.generated.ts"), entry).toBe(
125
+ true,
126
+ );
127
+ expect(has(graph, "embedded/pack.generated.ts"), entry).toBe(false);
128
+ }
129
+ });
130
+
107
131
  it("the help path (buildProgram) imports no zod schema module", () => {
108
132
  const graph = staticImportGraph(
109
133
  resolve(here, "../kernel/project/cli/buildProgram.ts"),