@canonical/pragma-cli 0.33.0 → 0.34.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 (250) hide show
  1. package/README.md +7 -7
  2. package/dist/pragma +0 -0
  3. package/package.json +18 -15
  4. package/pragma.conf.ts +664 -0
  5. package/src/bin.ts +13 -4
  6. package/src/capabilities/block.parity.test.ts +250 -0
  7. package/src/capabilities/capabilities/capabilities.render.ts +3 -2
  8. package/src/capabilities/capabilities/capabilities.verb.ts +31 -13
  9. package/src/capabilities/capabilities/catalog.ts +18 -10
  10. package/src/capabilities/capabilities/hints.ts +13 -19
  11. package/src/capabilities/colophon/collectColophon.ts +34 -19
  12. package/src/capabilities/colophon/colophon.verb.ts +8 -4
  13. package/src/capabilities/colophon/types.ts +16 -7
  14. package/src/capabilities/config/collectConfigShow.test.ts +57 -0
  15. package/src/capabilities/config/collectConfigShow.ts +41 -4
  16. package/src/capabilities/config/fields.ts +0 -27
  17. package/src/capabilities/config/set.verb.ts +7 -3
  18. package/src/capabilities/config/show.render.test.ts +77 -5
  19. package/src/capabilities/config/show.render.ts +7 -12
  20. package/src/capabilities/config/show.verb.ts +4 -3
  21. package/src/capabilities/config/types.ts +8 -0
  22. package/src/capabilities/create/byteEquality.test.ts +78 -100
  23. package/src/capabilities/create/compiledCreate.subprocess.test.ts +52 -15
  24. package/src/capabilities/create/constants.ts +75 -0
  25. package/src/capabilities/create/create.mcp.test.ts +2 -2
  26. package/src/capabilities/create/create.test.ts +162 -15
  27. package/src/capabilities/create/create.verb.ts +140 -69
  28. package/src/capabilities/create/index.ts +2 -10
  29. package/src/capabilities/create/pickGenerator.ts +34 -28
  30. package/src/capabilities/create/templates.embedded.generated.ts +4 -29
  31. package/src/capabilities/create/types.ts +10 -6
  32. package/src/capabilities/{standard/parity.test.ts → distribution.parity.test.ts} +24 -14
  33. package/src/capabilities/distribution.test.ts +120 -0
  34. package/src/capabilities/distribution.ts +59 -0
  35. package/src/capabilities/doctor/checks/checkConfigFile.ts +6 -5
  36. package/src/capabilities/doctor/checks/checkKeStore.ts +2 -2
  37. package/src/capabilities/doctor/checks/checkMcpConfigured.ts +7 -6
  38. package/src/capabilities/doctor/checks/checkPackageRefs.ts +79 -45
  39. package/src/capabilities/doctor/checks/checkPragmaVersion.ts +3 -2
  40. package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +61 -11
  41. package/src/capabilities/doctor/checks/checkShellCompletions.ts +63 -23
  42. package/src/capabilities/doctor/checks/checkSkillsSymlinked.ts +3 -2
  43. package/src/capabilities/doctor/doctor.render.test.ts +6 -6
  44. package/src/capabilities/doctor/doctor.render.ts +2 -1
  45. package/src/capabilities/doctor/doctor.test.ts +37 -8
  46. package/src/capabilities/doctor/doctor.verb.ts +6 -2
  47. package/src/capabilities/doctor/runChecks.ts +5 -5
  48. package/src/capabilities/doctor/types.ts +1 -1
  49. package/src/capabilities/emptyRecovery.test.ts +32 -15
  50. package/src/capabilities/graph/inspect.verb.ts +3 -2
  51. package/src/capabilities/graph/query.verb.ts +3 -2
  52. package/src/capabilities/graph/runQuery.ts +8 -5
  53. package/src/capabilities/index.ts +22 -18
  54. package/src/capabilities/info/collectInfo.ts +10 -6
  55. package/src/capabilities/info/info.render.ts +3 -2
  56. package/src/capabilities/info/info.verb.ts +3 -2
  57. package/src/capabilities/lazy.test.ts +93 -2
  58. package/src/capabilities/ontology/verbs.ts +21 -21
  59. package/src/capabilities/prompt/prompt.test.ts +12 -6
  60. package/src/capabilities/prompt/verbs.ts +24 -11
  61. package/src/capabilities/resources/provider.ts +30 -11
  62. package/src/capabilities/resources/resources.test.ts +85 -29
  63. package/src/capabilities/setup/operations/setupGenerator.ts +16 -9
  64. package/src/capabilities/setup/operations/setupMcp.ts +2 -2
  65. package/src/capabilities/setup/operations/setupSkills.ts +3 -3
  66. package/src/capabilities/setup/setup.verb.ts +12 -5
  67. package/src/capabilities/setup/shell.ts +29 -3
  68. package/src/capabilities/skill/discover.ts +11 -5
  69. package/src/capabilities/skill/render.ts +4 -5
  70. package/src/capabilities/skill/verbs.ts +7 -7
  71. package/src/capabilities/sources/collectStatus.ts +55 -50
  72. package/src/capabilities/sources/index.ts +1 -1
  73. package/src/capabilities/sources/installSkills.ts +2 -2
  74. package/src/capabilities/sources/runUpdate.ts +113 -122
  75. package/src/capabilities/sources/sources.test.ts +111 -117
  76. package/src/capabilities/sources/status.render.test.ts +53 -24
  77. package/src/capabilities/sources/status.render.ts +24 -29
  78. package/src/capabilities/sources/status.verb.ts +15 -8
  79. package/src/capabilities/sources/types.ts +18 -25
  80. package/src/capabilities/sources/update.render.ts +9 -2
  81. package/src/capabilities/sources/update.verb.ts +12 -23
  82. package/src/capabilities/surface.test.ts +33 -10
  83. package/src/capabilities/tier.parity.test.ts +144 -0
  84. package/src/capabilities/upgrade/upgrade.verb.ts +7 -3
  85. package/src/constants.test.ts +8 -6
  86. package/src/constants.ts +47 -21
  87. package/src/identity.test.ts +333 -0
  88. package/src/index.ts +2 -2
  89. package/src/kernel/completion/__snapshots__/emitScripts.test.ts.snap +5 -2
  90. package/src/kernel/completion/emitScripts.test.ts +1 -1
  91. package/src/kernel/completion/emitScripts.ts +4 -2
  92. package/src/kernel/completion/entitySource.test.ts +185 -41
  93. package/src/kernel/completion/entitySource.ts +117 -107
  94. package/src/kernel/completion/model.test.ts +1 -1
  95. package/src/kernel/completion/model.ts +11 -0
  96. package/src/kernel/completion/safety.test.ts +82 -36
  97. package/src/kernel/completion/shellDrive.test.ts +592 -0
  98. package/src/kernel/completion/templates/fish.ts +28 -6
  99. package/src/kernel/completion/types.ts +3 -3
  100. package/src/kernel/config/__snapshots__/firstRun.test.ts.snap +1 -1
  101. package/src/kernel/config/defaults.test.ts +85 -0
  102. package/src/kernel/config/defaults.ts +12 -23
  103. package/src/kernel/config/evaluateProjectConfig.ts +2 -3
  104. package/src/kernel/config/findProjectConfig.ts +4 -3
  105. package/src/kernel/config/firstRun.ts +12 -5
  106. package/src/kernel/config/globalConfig.ts +2 -2
  107. package/src/kernel/config/index.ts +4 -5
  108. package/src/kernel/config/paths.ts +17 -17
  109. package/src/kernel/config/readConfig.test.ts +242 -6
  110. package/src/kernel/config/readConfig.ts +8 -8
  111. package/src/kernel/config/schema.test.ts +50 -0
  112. package/src/kernel/config/schema.ts +97 -10
  113. package/src/kernel/config/types.ts +73 -19
  114. package/src/kernel/copy.test.ts +453 -0
  115. package/src/kernel/error/PragmaError.test.ts +1 -1
  116. package/src/kernel/error/constants.ts +3 -2
  117. package/src/kernel/error/index.ts +1 -1
  118. package/src/kernel/error/recovery.test.ts +22 -45
  119. package/src/kernel/error/recovery.ts +22 -27
  120. package/src/kernel/error/types.ts +5 -4
  121. package/src/kernel/packs/collect.test.ts +195 -11
  122. package/src/kernel/packs/collect.ts +213 -58
  123. package/src/kernel/packs/compile.test.ts +163 -7
  124. package/src/kernel/packs/compile.ts +15 -12
  125. package/src/kernel/packs/disclosure.test.ts +5 -2
  126. package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +11 -10
  127. package/src/kernel/packs/graphqlSource.test.ts +6 -3
  128. package/src/kernel/packs/iri.ts +5 -7
  129. package/src/kernel/packs/renderPack.ts +5 -3
  130. package/src/kernel/packs/resolveEntity.ts +21 -17
  131. package/src/kernel/packs/runBodies.ts +15 -14
  132. package/src/kernel/packs/schema.ts +96 -10
  133. package/src/kernel/packs/sparql/runSelect.test.ts +104 -10
  134. package/src/kernel/packs/sparql/runSelect.ts +73 -34
  135. package/src/kernel/packs/toolDescription.test.ts +10 -2
  136. package/src/kernel/packs/types.ts +39 -4
  137. package/src/kernel/packs/uniqueness.ts +4 -4
  138. package/src/kernel/project/cli/buildProgram.test.ts +9 -4
  139. package/src/kernel/project/cli/dispatch.test.ts +67 -0
  140. package/src/kernel/project/cli/dispatch.ts +34 -12
  141. package/src/kernel/project/cli/helpFormat.ts +1 -1
  142. package/src/kernel/project/cli/rootHelp.ts +105 -105
  143. package/src/kernel/project/mcp/buildServer.ts +11 -6
  144. package/src/kernel/project/mcp/instructions.ts +11 -6
  145. package/src/kernel/project/mcp/parity.test.ts +39 -1
  146. package/src/kernel/project/mcp/prompts/prompts.test.ts +120 -5
  147. package/src/kernel/project/mcp/prompts/provider.ts +22 -8
  148. package/src/kernel/project/mcp/prompts/source.ts +68 -67
  149. package/src/kernel/project/mcp/registerVerb.ts +25 -6
  150. package/src/kernel/project/mcp/serve.ts +11 -3
  151. package/src/kernel/project/mcp/toolDescriptions.test.ts +6 -2
  152. package/src/kernel/render/disclosure.ts +4 -2
  153. package/src/kernel/render/prefixes.test.ts +36 -0
  154. package/src/kernel/render/prefixes.ts +40 -13
  155. package/src/kernel/render/renderers.test.ts +1 -1
  156. package/src/kernel/runtime/graphpack/build.ts +29 -3
  157. package/src/kernel/runtime/graphpack/buildIndex.test.ts +46 -0
  158. package/src/kernel/runtime/graphpack/buildIndex.ts +52 -17
  159. package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +5 -5
  160. package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +3 -3
  161. package/src/kernel/runtime/graphpack/embedded/pack.stories.generated.ts +3 -0
  162. package/src/kernel/runtime/graphpack/embedded.ts +37 -11
  163. package/src/kernel/runtime/graphpack/graphpack.test.ts +205 -5
  164. package/src/kernel/runtime/graphpack/hash.ts +3 -2
  165. package/src/kernel/runtime/graphpack/index.ts +1 -1
  166. package/src/kernel/runtime/graphpack/manifest.ts +114 -12
  167. package/src/kernel/runtime/graphpack/read.ts +4 -9
  168. package/src/kernel/runtime/graphpack/schemas.ts +74 -0
  169. package/src/kernel/runtime/graphpack/stories.ts +84 -0
  170. package/src/kernel/runtime/graphpack/types.ts +61 -48
  171. package/src/kernel/runtime/paths.ts +64 -15
  172. package/src/kernel/runtime/probe.test.ts +8 -4
  173. package/src/kernel/runtime/readEntity.ts +6 -5
  174. package/src/kernel/runtime/refs/gitOps.ts +1 -19
  175. package/src/kernel/runtime/refs/parseRef.ts +7 -7
  176. package/src/kernel/runtime/refs/resolve.ts +78 -62
  177. package/src/kernel/runtime/resolveSources.test.ts +63 -24
  178. package/src/kernel/runtime/resolveSources.ts +36 -25
  179. package/src/kernel/runtime/storeReadiness.ts +9 -8
  180. package/src/kernel/runtime/storeless.test.ts +1 -1
  181. package/src/kernel/runtime/wasmEmbed.test.ts +22 -19
  182. package/src/kernel/spec/emitReference.test.ts +3 -3
  183. package/src/kernel/spec/emitReference.ts +144 -11
  184. package/src/kernel/spec/emitSurface.ts +9 -5
  185. package/src/kernel/spec/surfaceConformance.test.ts +2 -2
  186. package/src/kernel/spec/surfaceConformance.ts +8 -0
  187. package/src/kernel/spec/types.ts +29 -9
  188. package/src/kernel/spec/validate.ts +2 -1
  189. package/src/kernel/vocabulary.test.ts +164 -0
  190. package/src/kernel/vocabulary.ts +146 -0
  191. package/src/testing/PARITY_GAPS.ts +8 -2
  192. package/src/testing/behavioral/README.md +3 -3
  193. package/src/testing/behavioral/completion.test.ts +19 -6
  194. package/src/testing/behavioral/errorMatrix.mcp.test.ts +4 -3
  195. package/src/testing/behavioral/errorMatrix.storeless.test.ts +1 -1
  196. package/src/testing/behavioral/exitCodes.e2e.test.ts +6 -5
  197. package/src/testing/behavioral/harness.foundation.test.ts +14 -5
  198. package/src/testing/behavioral/journeys.cli.test.ts +116 -75
  199. package/src/testing/behavioral/journeys.defaultPack.test.ts +82 -176
  200. package/src/testing/behavioral/journeys.firstInstall.test.ts +167 -0
  201. package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +9 -6
  202. package/src/testing/behavioral/journeys.packageStories.test.ts +188 -0
  203. package/src/testing/behavioral/liveReadSurface.ts +4 -3
  204. package/src/testing/behavioral/mcpSurface.test.ts +9 -4
  205. package/src/testing/behavioral/staleCommands.test.ts +10 -0
  206. package/src/testing/eval/__snapshots__/eval.test.ts.snap +7 -7
  207. package/src/testing/eval/cases/assembly.ts +13 -6
  208. package/src/testing/eval/cases/effectful.ts +25 -13
  209. package/src/testing/eval/cases/readNouns.ts +22 -20
  210. package/src/testing/eval/cases/stable.ts +5 -1
  211. package/src/testing/eval/eval.test.ts +7 -1
  212. package/src/testing/fixtures/fixtureCapability.ts +45 -1
  213. package/src/testing/fixtures/graph/canonical.ts +6 -3
  214. package/src/testing/fixtures/graph/defaultPack.ts +6 -5
  215. package/src/testing/fixtures/graph/owlExport.ts +7 -5
  216. package/src/testing/helpers/fixtureGraph.ts +33 -16
  217. package/src/testing/helpers/packRuntime.ts +2 -3
  218. package/src/testing/helpers/projectCli.ts +2 -1
  219. package/src/testing/helpers/projectMcp.ts +6 -0
  220. package/src/testing/perf/budgets.test.ts +4 -0
  221. package/src/testing/perf/budgets.ts +22 -7
  222. package/src/testing/perf/globalSetup.ts +121 -6
  223. package/src/types.ts +2 -2
  224. package/src/capabilities/block/blockList.test.ts +0 -79
  225. package/src/capabilities/block/blockList.verb.ts +0 -163
  226. package/src/capabilities/block/index.ts +0 -25
  227. package/src/capabilities/block/pack.ts +0 -166
  228. package/src/capabilities/block/parity.test.ts +0 -187
  229. package/src/capabilities/block/tierChain.ts +0 -78
  230. package/src/capabilities/colophon/pragmaColophon.ts +0 -66
  231. package/src/capabilities/modifier/index.ts +0 -15
  232. package/src/capabilities/modifier/pack.ts +0 -64
  233. package/src/capabilities/standard/index.ts +0 -18
  234. package/src/capabilities/standard/pack.ts +0 -128
  235. package/src/capabilities/tier/index.ts +0 -19
  236. package/src/capabilities/tier/lookup.render.test.ts +0 -72
  237. package/src/capabilities/tier/lookup.render.ts +0 -59
  238. package/src/capabilities/tier/lookup.test.ts +0 -83
  239. package/src/capabilities/tier/lookup.verb.ts +0 -44
  240. package/src/capabilities/tier/pack.ts +0 -28
  241. package/src/capabilities/tier/runLookup.ts +0 -87
  242. package/src/capabilities/token/addConfig.render.ts +0 -27
  243. package/src/capabilities/token/addConfig.test.ts +0 -62
  244. package/src/capabilities/token/addConfig.verb.ts +0 -40
  245. package/src/capabilities/token/index.ts +0 -19
  246. package/src/capabilities/token/pack.ts +0 -58
  247. package/src/capabilities/token/runAddConfig.ts +0 -95
  248. package/src/kernel/completion/bashDrive.test.ts +0 -73
  249. package/src/kernel/runtime/graphpack/embedded/sample.ttl +0 -39
  250. package/src/kernel/runtime/lock.ts +0 -90
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Test helper: boot a store-backed {@link PragmaRuntime} at a REAL `cwd` whose
3
- * `pragma.lock.json` points at a built fixture pack.
3
+ * active-pack pointer names a built fixture pack.
4
4
  *
5
5
  * This is distinct from (and complements) `packRuntime.ts#buildFixtureRuntime`:
6
6
  * that helper hands back an in-process runtime wired to a custom `LazyStore`,
@@ -8,14 +8,18 @@
8
8
  * generalizes the `runtimeFor` + `buildUpdateTask` pattern proven in
9
9
  * `capabilities/sources/sources.test.ts`: it writes an actual
10
10
  * `pragma.config.ts` + package directory, runs the REAL `sources update` Task
11
- * (resolve → build → lock), and returns a `cwd`. Because the lock is a real
12
- * file, EVERY independent runtime construction that resolves config from that
11
+ * (resolve → build → point), and returns a `cwd`. Because the pointer is a
12
+ * real file, EVERY independent runtime construction that resolves config from that
13
13
  * `cwd` — `bootRuntime(flags, cwd)` (CLI dispatch), `projectMcp(modules, cwd)`
14
14
  * (MCP), and `runCli(args, { cwd })` (spawn) — boots the SAME cached pack. That
15
15
  * is the property PR4's cross-surface parity tests need and PR3's single-surface
16
16
  * parity tests did not: proof that CLI-json and MCP-json agree over a graph
17
17
  * built the same way `sources update` builds one for a real project.
18
18
  *
19
+ * A fixture package may also ship `stories/*.json` (the `stories` option), which
20
+ * `sources update` carries into the built pack — that is the package tier a
21
+ * third-party noun arrives through.
22
+ *
19
23
  * Hermetic: the pack cache lives under the isolated `$XDG_CACHE_HOME`
20
24
  * `setupXdgIsolation` installs; `dispose()` removes the temp directories (the
21
25
  * shared content-addressed pack cache itself is left for reuse/cleanup by the
@@ -30,7 +34,7 @@ import { buildUpdateTask } from "../../capabilities/sources/runUpdate.js";
30
34
  import { VERSION } from "../../constants.js";
31
35
  import type {
32
36
  ConfigLayers,
33
- PackageEntry,
37
+ PackDeclaration,
34
38
  PragmaConfig,
35
39
  } from "../../kernel/config/types.js";
36
40
  import { bootRuntime } from "../../kernel/runtime/boot.js";
@@ -52,34 +56,39 @@ export interface FixtureGraphOptions {
52
56
  readonly ttl: string;
53
57
  /**
54
58
  * Config fields to bake into the written `pragma.config.ts`, e.g.
55
- * `{ tier: "apps/lxd", channel: "prerelease" }`. `packages` is always set by
59
+ * `{ tier: "apps/lxd", channel: "prerelease" }`. `packs` is always set by
56
60
  * this helper (to the fixture package) — do not override it here.
57
61
  */
58
- readonly config?: Omit<Partial<PragmaConfig>, "packages">;
62
+ readonly config?: Omit<Partial<PragmaConfig>, "packs">;
63
+ /**
64
+ * `stories/*.json` the fixture PACKAGE ships, as raw text keyed by file name
65
+ * — deliberately raw, so a test can ship malformed or schema-invalid content
66
+ * and assert that it is dropped rather than fatal.
67
+ */
68
+ readonly stories?: Readonly<Record<string, string>>;
59
69
  }
60
70
 
61
71
  /** A booted fixture runtime plus its `cwd` (usable by any surface) and disposal. */
62
72
  export interface FixtureGraph {
63
73
  /** A REAL `bootRuntime` at {@link cwd} — the same one CLI dispatch uses. */
64
74
  readonly runtime: PragmaRuntime;
65
- /** The project directory whose `pragma.lock.json`/`pragma.config.ts` were written. */
75
+ /** The project directory whose `pragma.config.ts` + active-pack pointer were written. */
66
76
  readonly cwd: string;
67
77
  /** Remove the temp directories and dispose the store session, if booted. */
68
78
  dispose(): Promise<void>;
69
79
  }
70
80
 
71
81
  /** A synthetic runtime with an IN-MEMORY config — used only to drive the build Task. */
72
- function builderRuntime(cwd: string, packages: PackageEntry[]): PragmaRuntime {
82
+ function builderRuntime(cwd: string, packs: PackDeclaration[]): PragmaRuntime {
73
83
  const layers: ConfigLayers = {
74
- config: { channel: "normal", packages },
84
+ config: { channel: "normal", packs },
75
85
  origins: {
76
86
  tier: "default",
77
87
  channel: "default",
78
88
  detail: "default",
79
- packages: "project",
89
+ packs: "project",
80
90
  stories: "default",
81
91
  prefixes: "default",
82
- prompts: "default",
83
92
  },
84
93
  global: { path: "/nonexistent", exists: false },
85
94
  project: { exists: false },
@@ -102,8 +111,9 @@ function configField(key: string, value: unknown): string {
102
111
  }
103
112
 
104
113
  /**
105
- * Build a store-backed runtime whose `cwd` carries a real lock file — the ONE
106
- * shared store-backed fixture path for cross-surface (CLI/MCP/spawn) tests.
114
+ * Build a store-backed runtime whose `cwd` is pointed at a real built pack —
115
+ * the ONE shared store-backed fixture path for cross-surface (CLI/MCP/spawn)
116
+ * tests.
107
117
  *
108
118
  * @param options - The fixture graph TTL and any config overrides.
109
119
  * @returns The runtime, its cwd, and a disposer.
@@ -116,11 +126,18 @@ export async function bootFixtureRuntime(
116
126
  const pkgDir = mkdtempSync(join(tmpdir(), "pragma-fixture-pkg-"));
117
127
  mkdirSync(join(pkgDir, "definitions"), { recursive: true });
118
128
  writeFileSync(join(pkgDir, "definitions", "fixture.ttl"), options.ttl);
129
+ const stories = Object.entries(options.stories ?? {});
130
+ if (stories.length > 0) {
131
+ mkdirSync(join(pkgDir, "stories"), { recursive: true });
132
+ for (const [file, content] of stories) {
133
+ writeFileSync(join(pkgDir, "stories", file), content);
134
+ }
135
+ }
119
136
 
120
- const packages: PackageEntry[] = [
137
+ const packs: PackDeclaration[] = [
121
138
  { name: "fixture", source: `file://${pkgDir}` },
122
139
  ];
123
- const fields = [configField("packages", packages)];
140
+ const fields = [configField("packs", packs)];
124
141
  for (const [key, value] of Object.entries(options.config ?? {})) {
125
142
  fields.push(configField(key, value));
126
143
  }
@@ -129,7 +146,7 @@ export async function bootFixtureRuntime(
129
146
  `export default {\n${fields.join("\n")}\n};\n`,
130
147
  );
131
148
 
132
- await runTask(await buildUpdateTask(builderRuntime(cwd, packages), false));
149
+ await runTask(await buildUpdateTask(builderRuntime(cwd, packs)));
133
150
 
134
151
  const runtime = bootRuntime(FIXTURE_FLAGS, cwd);
135
152
 
@@ -36,7 +36,7 @@ export interface FixtureRuntimeOptions {
36
36
  /** Explicit `--detail` level for this invocation. */
37
37
  readonly detail?: DetailLevel;
38
38
  /** Config `detail` value and its origin (drives {@link resolvePackDetail}). */
39
- readonly configDetail?: string;
39
+ readonly configDetail?: DetailLevel;
40
40
  /** Origin of the config `detail` (default `"default"`). */
41
41
  readonly detailOrigin?: ConfigOrigin;
42
42
  }
@@ -93,10 +93,9 @@ export async function buildFixtureRuntime(
93
93
  tier: "default",
94
94
  channel: "default",
95
95
  detail: options.detailOrigin ?? "default",
96
- packages: "default",
96
+ packs: "default",
97
97
  stories: "default",
98
98
  prefixes: "default",
99
- prompts: "default",
100
99
  },
101
100
  global: { path: "", exists: false },
102
101
  project: { exists: false },
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import type { Command } from "commander";
10
+ import { BIN_NAME } from "../../constants.js";
10
11
  import { buildProgram } from "../../kernel/project/cli/buildProgram.js";
11
12
  import type { GlobalFlags } from "../../kernel/runtime/types.js";
12
13
  import type { CapabilityModule, VerbSpec } from "../../kernel/spec/types.js";
@@ -31,5 +32,5 @@ export function projectCli(
31
32
  globalFlags: GlobalFlags = TEST_FLAGS,
32
33
  ): Command {
33
34
  const verbs: VerbSpec[] = modules.flatMap((module) => [...module.verbs]);
34
- return buildProgram(verbs, { globalFlags, programName: "pragma" });
35
+ return buildProgram(verbs, { globalFlags, programName: BIN_NAME });
35
36
  }
@@ -42,6 +42,8 @@ export interface McpHarness {
42
42
  completeResource(partial: string): Promise<string[]>;
43
43
  /** The server capabilities negotiated at initialize (tools/resources/prompts). */
44
44
  serverCapabilities(): ServerCapabilities | undefined;
45
+ /** The `serverInfo` the server introduced itself with at initialize. */
46
+ serverInfo(): { name: string; version: string } | undefined;
45
47
  /** The server `instructions` string sent at initialize. */
46
48
  instructions(): string | undefined;
47
49
  /** List the native MCP prompts (`prompts/list`). */
@@ -120,6 +122,10 @@ export async function projectMcp(
120
122
  serverCapabilities() {
121
123
  return client.getServerCapabilities();
122
124
  },
125
+ serverInfo() {
126
+ const info = client.getServerVersion();
127
+ return info ? { name: info.name, version: info.version } : undefined;
128
+ },
123
129
  instructions() {
124
130
  return client.getInstructions();
125
131
  },
@@ -96,6 +96,10 @@ describe("perf budgets (PROTECTED)", () => {
96
96
  // __store-probe boots the embedded pack from its n-quads cache and queries
97
97
  // it — the full store-backed verb cost in the compiled binary. The first
98
98
  // spawn materializes the pack; warmups absorb it, then it is a cache hit.
99
+ // Note that with 9 kept samples a nearest-rank p95 IS the maximum (see
100
+ // BUDGETS.md's p95-stabilization section) — deliberately kept, because the
101
+ // honest statistic here is the one that catches real cost, and the ceiling
102
+ // is sized with a 1.25× margin over a projected p95 to absorb it.
99
103
  const result = measureCommand(BINARY, ["__store-probe"], {
100
104
  runs: 12,
101
105
  warmups: 3,
@@ -4,9 +4,12 @@
4
4
  * The ceilings the protected budget tests assert against. The surface
5
5
  * covenant's designed target for `--help`/`__complete` is 50 ms; the day-1 perf
6
6
  * spike (commit 6) found that unrealistic on the build hardware (cold Bun
7
- * process start alone is ~45 ms here), so — per the plan — each ceiling is set
8
- * to roughly 2× the measured median rather than silently weakening the target.
9
- * Measured numbers and environment are recorded in BUDGETS.md.
7
+ * process start alone is ~45 ms here), so — per the plan — those ceilings are
8
+ * set to roughly 2× the measured median rather than silently weakening the
9
+ * target. {@link BUDGET_WARM_STORE_MS} is derived differently (from a projected
10
+ * p95, and it lands TIGHTER than 2× its median); its arithmetic is written out
11
+ * in full in BUDGETS.md, as are the measurements and environment for all of
12
+ * them.
10
13
  */
11
14
 
12
15
  /** `pragma --help` ceiling (ms). Designed 50; measured median ~61 → 2×. */
@@ -20,11 +23,23 @@ export const BUDGET_PROJECT_CONFIG_MS = 10;
20
23
 
21
24
  /**
22
25
  * Warm store-backed verb ceiling (ms) — a store boot from the cached n-quads
23
- * dump plus a query, in the compiled binary. The designed 300 ms holds: the
24
- * measured median (`__store-probe`) is ~150 ms here, so 300 is already ~2× the
25
- * measured median and needs no relaxation (see BUDGETS.md).
26
+ * dump plus a query, in the compiled binary.
27
+ *
28
+ * Re-derived when the embed became the distribution's real 8 479-triple graph
29
+ * instead of a 23-triple sample. Netted against a `--version` control from the
30
+ * SAME binary in the SAME run (this box's process start swings 60–287 ms with
31
+ * page-cache state alone), the real pack's store work is 2.83× the sample's —
32
+ * the median of five repetitions across two protocols. Projected onto the
33
+ * reference box, whose own toy store work is 147 − 45.5 = 101.5 ms: 45.5 +
34
+ * 101.5 × 2.83 ≈ 333 ms median, and 333 × (176/147) ≈ 398 ms p95 using the
35
+ * reference box's own dispersion for this command. `ceil(398 × 1.25 / 50) × 50`
36
+ * = 500 — which is 1.6× the projected median, i.e. tighter than the
37
+ * 2×-of-median rule the ceilings above use. Every input, every step, and the
38
+ * raw measurements are in BUDGETS.md; the designed `<300ms` target stays in the
39
+ * surface covenant, exactly as the 50 ms `help` target survived its 130 ms
40
+ * ceiling.
26
41
  */
27
- export const BUDGET_WARM_STORE_MS = 300;
42
+ export const BUDGET_WARM_STORE_MS = 500;
28
43
 
29
44
  /**
30
45
  * Warm in-process MCP tool-call ceiling (ms) — PR7 graduates this from seeded to
@@ -1,24 +1,139 @@
1
1
  /**
2
2
  * Vitest global setup: build the compiled `dist/pragma` once, before the suite,
3
- * if it is missing.
3
+ * if it is missing OR older than the sources it was built from.
4
4
  *
5
5
  * Shared by both configs, because two suites spawn the binary: the perf budgets
6
6
  * (src/testing/perf/**, `test:perf`) and the storeless-guarantee guards in
7
7
  * src/kernel/completion/safety.test.ts (the main `test:vitest` pass). Wiring it
8
8
  * into both means `bun run test` on a clean checkout provisions the binary with
9
9
  * no manual build step — neither suite may assume it is pre-built.
10
+ *
11
+ * STALENESS, not mere existence. `existsSync` alone meant every spawned-binary
12
+ * guard ran against whatever binary happened to be on disk: a mutation to
13
+ * `bin.ts` making the storeless `__complete` path write to `$HOME` and boot the
14
+ * store — precisely what `safety.test.ts` is PROTECTED to forbid — was live
15
+ * when run from source and invisible through the gate. The guard whose own
16
+ * docblock warns that an unreachable bundle "would leave the whole suite green"
17
+ * was itself green against a binary that predated the change under test.
18
+ *
19
+ * STALENESS INCLUDES THE EMBEDDED WORKSPACE DEPS. The binary bundles every
20
+ * `@canonical/*` workspace package it (transitively) imports — task, summon-*,
21
+ * ke, … — so an edit to `packages/runtime/task` is a change to what
22
+ * `dist/pragma` runs, yet this package's own `src` never moves. The gate
23
+ * therefore also watches each workspace-linked dependency (found by following
24
+ * the `node_modules/<name>` symlinks, transitively) — its `src` (the authored
25
+ * source), `dist` (what the bundler actually embeds, per the dep's export map)
26
+ * and `package.json`. Registry deps resolve into a `node_modules` store path
27
+ * and are skipped: their content only changes with a lockfile change, which
28
+ * `bun install` surfaces as a fresh symlink mtime anyway. Content hashing of
29
+ * the build inputs was considered and DECLINED (PR7 ruling R5): an mtime
30
+ * comparison is a handful of stats, needs no state file to compare against,
31
+ * and the failure mode of a false "stale" is one redundant 10 s build — while
32
+ * hashing every input on every suite start costs more than the rebuild it
33
+ * avoids. CI is fresh-checkout either way; this gate exists for developer
34
+ * boxes that have built before.
10
35
  */
11
36
 
12
37
  import { spawnSync } from "node:child_process";
13
- import { existsSync } from "node:fs";
38
+ import { lstatSync, readdirSync, realpathSync, statSync } from "node:fs";
39
+ import { join, sep } from "node:path";
14
40
  import { fileURLToPath } from "node:url";
15
41
 
42
+ /** Everything the compiled binary is built FROM, relative to the package root. */
43
+ const INPUTS = ["src", "scripts", "pragma.conf.ts", "package.json"];
44
+
45
+ /**
46
+ * What feeds the binary inside one workspace dependency: its authored source,
47
+ * the compiled output the bundler embeds, and its manifest. Deliberately NOT
48
+ * the whole package dir — that would watch `coverage/` and `node_modules/`,
49
+ * whose mtimes move on every test run and would force a rebuild loop.
50
+ */
51
+ const DEP_INPUTS = ["src", "dist", "package.json"];
52
+
53
+ /**
54
+ * The newest modification time under `path`, or 0 when it does not exist.
55
+ * A nested `node_modules` is never descended into (a dep's own deps are
56
+ * enumerated as roots of their own by {@link workspaceDepRoots}).
57
+ *
58
+ * @param path - A file or directory.
59
+ * @returns Epoch milliseconds of the newest entry beneath it.
60
+ * @note Impure — stats the source tree.
61
+ */
62
+ function newestMtime(path: string): number {
63
+ let stats: ReturnType<typeof statSync>;
64
+ try {
65
+ stats = statSync(path);
66
+ } catch {
67
+ return 0;
68
+ }
69
+ if (!stats.isDirectory()) return stats.mtimeMs;
70
+ let newest = stats.mtimeMs;
71
+ for (const entry of readdirSync(path)) {
72
+ if (entry === "node_modules") continue;
73
+ newest = Math.max(newest, newestMtime(join(path, entry)));
74
+ }
75
+ return newest;
76
+ }
77
+
78
+ /**
79
+ * Every workspace package the binary can embed, transitively: follow each
80
+ * `node_modules/<name>` symlink whose target lives OUTSIDE any `node_modules`
81
+ * store (that is what distinguishes a workspace link from a registry install),
82
+ * then repeat from the target's own `node_modules`. Cycles are cut by the
83
+ * visited set.
84
+ *
85
+ * @param pkgRoot - This package's root directory.
86
+ * @returns Absolute real paths of the linked workspace dependency roots.
87
+ * @note Impure — reads `node_modules` link farms.
88
+ */
89
+ function workspaceDepRoots(pkgRoot: string): string[] {
90
+ const visited = new Set<string>([realpathSync(pkgRoot)]);
91
+ const queue = [realpathSync(pkgRoot)];
92
+ while (queue.length > 0) {
93
+ const dir = queue.pop() as string;
94
+ const nm = join(dir, "node_modules");
95
+ let entries: string[];
96
+ try {
97
+ entries = readdirSync(nm);
98
+ } catch {
99
+ continue;
100
+ }
101
+ const links = entries.flatMap((entry) => {
102
+ if (!entry.startsWith("@")) return [join(nm, entry)];
103
+ try {
104
+ return readdirSync(join(nm, entry)).map((e) => join(nm, entry, e));
105
+ } catch {
106
+ return [];
107
+ }
108
+ });
109
+ for (const link of links) {
110
+ let real: string;
111
+ try {
112
+ if (!lstatSync(link).isSymbolicLink()) continue;
113
+ real = realpathSync(link);
114
+ } catch {
115
+ continue;
116
+ }
117
+ if (real.split(sep).includes("node_modules")) continue;
118
+ if (visited.has(real)) continue;
119
+ visited.add(real);
120
+ queue.push(real);
121
+ }
122
+ }
123
+ const root = realpathSync(pkgRoot);
124
+ return [...visited].filter((dir) => dir !== root);
125
+ }
126
+
16
127
  export default function setup(): void {
17
128
  const root = fileURLToPath(new URL("../../../", import.meta.url));
18
- const binary = fileURLToPath(
19
- new URL("../../../dist/pragma", import.meta.url),
20
- );
21
- if (existsSync(binary)) return;
129
+ const built = newestMtime(join(root, "dist", "pragma"));
130
+ const fresh =
131
+ built > 0 &&
132
+ INPUTS.every((input) => newestMtime(join(root, input)) < built) &&
133
+ workspaceDepRoots(root).every((dep) =>
134
+ DEP_INPUTS.every((input) => newestMtime(join(dep, input)) < built),
135
+ );
136
+ if (fresh) return;
22
137
 
23
138
  const result = spawnSync("bun", ["run", "scripts/build.ts"], {
24
139
  cwd: root,
package/src/types.ts CHANGED
@@ -12,8 +12,8 @@ export type { DetailLevel, OutputFormat } from "./constants.js";
12
12
  // — Config authoring ————————————————————————————————————————————————————————
13
13
  export type {
14
14
  Channel,
15
- PackageDeclaration,
16
- PackageEntry,
15
+ PackDeclaration,
16
+ PackSource,
17
17
  PragmaConfig,
18
18
  } from "./kernel/config/types.js";
19
19
  // — Error model —————————————————————————————————————————————————————————————
@@ -1,79 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
- import { verbKey } from "../../kernel/packs/uniqueness.js";
3
- import type { PragmaRuntime } from "../../kernel/runtime/types.js";
4
- import type { VerbSpec } from "../../kernel/spec/types.js";
5
- import { OWL_EXPORT_TTL } from "../../testing/fixtures/graph/owlExport.js";
6
- import { bootFixtureRuntime } from "../../testing/helpers/fixtureGraph.js";
7
- import type { BlockRow } from "./blockList.verb.js";
8
- import { blockModule } from "./index.js";
9
-
10
- const listVerb = blockModule.verbs.find(
11
- (verb) => verbKey(verb.path) === "block list",
12
- ) as VerbSpec;
13
-
14
- const names = (rows: BlockRow[]): string[] =>
15
- rows.map((row) => row.name).sort();
16
-
17
- /**
18
- * The OWL-export fixture ships an UNTIERED `ds:Component` (`ds:datePicker`, no
19
- * `ds:tier`) beside a tiered one (`ds:button`). The pre-fix `block list` gated
20
- * on a REQUIRED `ds:tier` triple pattern, so `--all-tiers` — which drops the
21
- * FILTER but not the pattern — still hid the untiered block, contradicting the
22
- * flag's promise to show every block (A2). A tier-scoped view legitimately
23
- * omits an untiered block (it joins the list through its tier); `--all-tiers`
24
- * is the escape that reveals it.
25
- */
26
- describe("block list — untiered blocks under --all-tiers (A2)", () => {
27
- describe("no tier configured", () => {
28
- let runtime: PragmaRuntime;
29
- let dispose: () => Promise<void>;
30
-
31
- beforeAll(async () => {
32
- const fixture = await bootFixtureRuntime({ ttl: OWL_EXPORT_TTL });
33
- runtime = fixture.runtime;
34
- dispose = fixture.dispose;
35
- });
36
- afterAll(() => dispose());
37
-
38
- it("the default view still omits the untiered block", async () => {
39
- const rows = (await listVerb.run({}, runtime)) as BlockRow[];
40
- expect(names(rows)).toEqual(["Button"]);
41
- });
42
-
43
- it("--all-tiers reveals the untiered block", async () => {
44
- const rows = (await listVerb.run(
45
- { allTiers: true },
46
- runtime,
47
- )) as BlockRow[];
48
- expect(names(rows)).toEqual(["Button", "Date Picker"]);
49
- });
50
- });
51
-
52
- describe("a tier IS configured", () => {
53
- let runtime: PragmaRuntime;
54
- let dispose: () => Promise<void>;
55
-
56
- beforeAll(async () => {
57
- const fixture = await bootFixtureRuntime({
58
- ttl: OWL_EXPORT_TTL,
59
- config: { tier: "global", channel: "normal" },
60
- });
61
- runtime = fixture.runtime;
62
- dispose = fixture.dispose;
63
- });
64
- afterAll(() => dispose());
65
-
66
- it("a scoped tier lists its tiered block, not the untiered one", async () => {
67
- const rows = (await listVerb.run({}, runtime)) as BlockRow[];
68
- expect(names(rows)).toEqual(["Button"]);
69
- });
70
-
71
- it("--all-tiers overrides the scope and reveals the untiered block", async () => {
72
- const rows = (await listVerb.run(
73
- { allTiers: true },
74
- runtime,
75
- )) as BlockRow[];
76
- expect(names(rows)).toContain("Date Picker");
77
- });
78
- });
79
- });
@@ -1,163 +0,0 @@
1
- /**
2
- * `block list` — the ONE hand-written read (Risk5).
3
- *
4
- * A block list is config-filtered in ways packs cannot express declaratively:
5
- * the tier CHAIN (a tier makes its whole parent chain visible), the channel
6
- * (release-level visibility), and the `--all-tiers` escape. Everything else in
7
- * PR3 is a declarative pack; this verb ports that behaviour directly. It reads
8
- * the effective tier/channel from config and runs one generated SELECT (no user
9
- * input in the query — the tier is config, the channel a closed enum).
10
- */
11
-
12
- import { runSelect } from "../../kernel/packs/sparql/runSelect.js";
13
- import type {
14
- ColumnDef,
15
- RenderListOptions,
16
- } from "../../kernel/render/contracts.js";
17
- import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
18
- import {
19
- renderListLlm,
20
- renderListPlain,
21
- } from "../../kernel/render/renderers.js";
22
- import type { PragmaRuntime } from "../../kernel/runtime/types.js";
23
- import { asVerb } from "../../kernel/spec/asVerb.js";
24
- import type { Formatters, VerbSpec } from "../../kernel/spec/types.js";
25
- import { buildChannelFilter, buildTierFilter } from "./tierChain.js";
26
-
27
- /** One block summary row. */
28
- export interface BlockRow {
29
- readonly uri: string;
30
- readonly name: string;
31
- readonly type: string;
32
- readonly tier: string;
33
- readonly modifiers: string;
34
- }
35
-
36
- /** Local name of an IRI (`…/global` → `global`; `…#Thing` → `Thing`). */
37
- function localName(uri: string): string {
38
- const hash = uri.lastIndexOf("#");
39
- if (hash !== -1) return uri.slice(hash + 1);
40
- const slash = uri.lastIndexOf("/");
41
- return slash !== -1 ? uri.slice(slash + 1) : uri;
42
- }
43
-
44
- /** Normalize a block's rdf:type to one of the four block kinds. */
45
- function normalizeType(typeUri: string | undefined): BlockRow["type"] {
46
- const local = localName(typeUri ?? "").toLowerCase();
47
- return local === "pattern" || local === "layout" || local === "subcomponent"
48
- ? local
49
- : "component";
50
- }
51
-
52
- const listColumns: ColumnDef<BlockRow>[] = [
53
- { key: "name", label: "Name" },
54
- { key: "type", label: "Type" },
55
- { key: "tier", label: "Tier" },
56
- { key: "modifiers", label: "Modifiers", showWhenEmpty: false },
57
- { key: "uri", label: "IRI" },
58
- ];
59
-
60
- const listOptions: RenderListOptions<BlockRow> = {
61
- heading: "Blocks",
62
- columns: listColumns,
63
- prefixes: DEFAULT_PREFIX_MAP,
64
- // Zero blocks is a calm success (exit 0), not an error — the list is scoped by
65
- // the active tier chain and channel, so the message names that scope and the
66
- // hint offers the escape hatches (a cold store fails earlier with
67
- // STORE_UNAVAILABLE, so reaching here means the store is built).
68
- emptyMessage: "No blocks found under the current tier and channel.",
69
- emptyHint:
70
- "Use --all-tiers to ignore the tier filter, or run `pragma sources update` if the store is empty.",
71
- };
72
-
73
- const listFormatters: Formatters<BlockRow[]> = {
74
- plain: (rows) => renderListPlain(rows, listOptions),
75
- llm: (rows) => renderListLlm(rows, listOptions),
76
- json: (rows) => JSON.stringify(rows, null, 2),
77
- };
78
-
79
- /** Build the config-filtered block SELECT for the resolved tier/channel. */
80
- function buildQuery(
81
- tier: string | undefined,
82
- channel: import("../../kernel/config/types.js").Channel,
83
- allTiers: boolean,
84
- ): string {
85
- const tierFilter = allTiers ? "" : buildTierFilter(tier);
86
- const channelFilter = buildChannelFilter(channel);
87
- // Under --all-tiers, `ds:name`/`ds:tier` become OPTIONAL so a real block that
88
- // ships without either is no longer hidden — the flag promises "all blocks",
89
- // yet the pre-fix query gated on those as REQUIRED patterns, dropping the
90
- // FILTER but not the pattern (A2). In the scoped/default view they stay
91
- // required: a block joins the list through its tier, so an untiered block is
92
- // intentionally out of a tier-scoped view (and --all-tiers is the escape).
93
- const nameTierPatterns = allTiers
94
- ? [
95
- " OPTIONAL { ?component ds:name ?name }",
96
- " OPTIONAL { ?component ds:tier ?tier }",
97
- ]
98
- : [" ?component ds:name ?name ; ds:tier ?tier ."];
99
- return [
100
- "SELECT ?component ?type ?name ?tier",
101
- ' (GROUP_CONCAT(DISTINCT ?modName; separator=", ") AS ?modifiers)',
102
- "WHERE {",
103
- " VALUES ?type { ds:Component ds:Pattern ds:Layout ds:Subcomponent }",
104
- " ?component a ?type .",
105
- ...nameTierPatterns,
106
- tierFilter ? ` ${tierFilter}` : "",
107
- ` ${channelFilter}`,
108
- " OPTIONAL { ?component ds:hasModifierFamily ?mod . ?mod ds:name ?modName }",
109
- "}",
110
- "GROUP BY ?component ?type ?name ?tier",
111
- "ORDER BY ?name",
112
- ]
113
- .filter((line) => line !== "")
114
- .join("\n");
115
- }
116
-
117
- const listVerb: VerbSpec<Record<string, unknown>, BlockRow[]> = {
118
- path: ["block", "list"],
119
- summary: "List blocks visible under the current tier and channel.",
120
- doc: "List design system blocks visible under the active tier chain and channel. Optionally list across every tier, ignoring the tier filter.",
121
- params: [
122
- {
123
- kind: "boolean",
124
- name: "allTiers",
125
- doc: "Show blocks from all tiers, ignoring the tier filter.",
126
- },
127
- ],
128
- output: { formatters: listFormatters },
129
- examples: [
130
- { cmd: "pragma block list" },
131
- { cmd: "pragma block list --all-tiers" },
132
- { cmd: "pragma block list --format llm" },
133
- ],
134
- capability: {
135
- needsStore: true,
136
- mutates: false,
137
- mcp: {
138
- expose: true,
139
- annotations: { readOnlyHint: true, openWorldHint: false },
140
- },
141
- },
142
- run: async (params: Record<string, unknown>, rt: PragmaRuntime) => {
143
- const layers = await rt.loadConfig();
144
- const query = buildQuery(
145
- layers.config.tier,
146
- layers.config.channel,
147
- params.allTiers === true,
148
- );
149
- const rows = await runSelect(rt, query, "block");
150
- return rows.map((row) => ({
151
- uri: row.component ?? "",
152
- // An unnamed block still needs a token to show — fall back to its IRI's
153
- // local name rather than rendering a blank row (A2).
154
- name: row.name ?? localName(row.component ?? ""),
155
- type: normalizeType(row.type),
156
- tier: localName(row.tier ?? ""),
157
- modifiers: row.modifiers ?? "",
158
- }));
159
- },
160
- };
161
-
162
- /** The hand-written `block list` verb. */
163
- export const blockListVerb = asVerb(listVerb);
@@ -1,25 +0,0 @@
1
- /**
2
- * The `block` capability module — a COMPOSITE: the hand-written `block list`
3
- * (tier chain + channel + --all-tiers) plus the bundled pack's GraphQL `lookup`.
4
- *
5
- * This is the one noun where a declarative pack and a hand-written verb share a
6
- * module; the pack ships lookup-only, so there is no `(noun, verb)` collision.
7
- */
8
-
9
- import { compilePack } from "../../kernel/packs/compile.js";
10
- import { DEFAULT_PREFIX_MAP } from "../../kernel/render/prefixes.js";
11
- import type { CapabilityModule } from "../../kernel/spec/types.js";
12
- import { blockListVerb } from "./blockList.verb.js";
13
- import { blockPack } from "./pack.js";
14
-
15
- /** The `block` capability module (`list` hand-written, `lookup` from the pack). */
16
- export const blockModule: CapabilityModule = {
17
- name: "block",
18
- verbs: [
19
- blockListVerb,
20
- ...compilePack(blockPack, "bundled:block", DEFAULT_PREFIX_MAP),
21
- ],
22
- // The bundled design-system domain colophon (authored on the flagship UI-block
23
- // noun), surfaced by `pragma colophon` after pragma's own.
24
- colophon: blockPack.colophon,
25
- };