@orkestrel/scaffold 0.0.63 → 0.0.65

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 (57) hide show
  1. package/README.md +29 -104
  2. package/dist/bin/main.js +95 -27
  3. package/dist/bin/main.js.map +1 -1
  4. package/dist/host/AGENTS.md +2 -2
  5. package/dist/host/CLAUDE.md +6 -0
  6. package/dist/host/agents/orchestration.md +23 -15
  7. package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +184 -177
  8. package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +314 -91
  9. package/dist/host/agents/skills/enterprise-bootstrap/references/color-modes.md +241 -0
  10. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +83 -36
  11. package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +297 -98
  12. package/dist/host/agents/skills/enterprise-bootstrap/references/inputs.md +25 -14
  13. package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +216 -128
  14. package/dist/host/agents/skills/enterprise-bootstrap/references/responsive-layout.md +187 -0
  15. package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +109 -20
  16. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +5 -5
  17. package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
  18. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +15 -15
  19. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +43 -17
  20. package/dist/host/agents/skills/orkestrel-publish/references/window.md +41 -16
  21. package/dist/host/claude/agents/orkestrel.md +56 -56
  22. package/dist/host/claude/agents/reviewer.md +13 -0
  23. package/dist/host/claude/rules/architecture.md +51 -45
  24. package/dist/host/claude/rules/documentation.md +18 -1
  25. package/dist/host/claude/rules/portability.md +2 -0
  26. package/dist/host/claude/rules/quality.md +1 -1
  27. package/dist/host/claude/rules/tests.md +12 -11
  28. package/dist/host/claude/rules/typescript.md +5 -0
  29. package/dist/host/claude/rules/workspace.md +25 -20
  30. package/dist/host/claude/rules/writing.md +4 -0
  31. package/dist/host/claude/settings.json +1 -1
  32. package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +10 -9
  33. package/dist/host/codex/agents/orkestrel.toml +3 -3
  34. package/dist/host/codex/agents/reviewer.toml +4 -2
  35. package/dist/host/configs/helpers.ts +311 -2
  36. package/dist/host/configs/policy.ts +1100 -51
  37. package/dist/host/dotfiles/oxlintrc.json +72 -1
  38. package/dist/host/guides/guide.md +749 -222
  39. package/dist/host/guides/scaffold.md +529 -394
  40. package/dist/host/manifest.json +53 -40
  41. package/dist/host/scripts/ollama.sh +322 -13
  42. package/dist/host/tests/config.test.ts +1200 -16
  43. package/dist/host/tests/policy.test.ts +157 -173
  44. package/dist/host/tests/setupPolicy.ts +522 -1007
  45. package/dist/src/core/index.cjs +402 -287
  46. package/dist/src/core/index.cjs.map +1 -1
  47. package/dist/src/core/index.d.cts +160 -128
  48. package/dist/src/core/index.d.ts +160 -128
  49. package/dist/src/core/index.js +400 -286
  50. package/dist/src/core/index.js.map +1 -1
  51. package/dist/src/server/index.cjs +28 -21
  52. package/dist/src/server/index.cjs.map +1 -1
  53. package/dist/src/server/index.d.cts +38 -33
  54. package/dist/src/server/index.d.ts +38 -33
  55. package/dist/src/server/index.js +28 -21
  56. package/dist/src/server/index.js.map +1 -1
  57. package/package.json +18 -19
@@ -3,8 +3,8 @@ import { fillTemplate } from "@orkestrel/template";
3
3
  import { Emitter } from "@orkestrel/emitter";
4
4
  var package_default = {
5
5
  name: "@orkestrel/scaffold",
6
- version: "0.0.63",
7
- description: "Scaffold workspaces with five commands: new, audit, repair, catalog, and overwrite.",
6
+ version: "0.0.65",
7
+ description: "Scaffold workspaces with commands: new, audit, repair, catalog, and overwrite.",
8
8
  keywords: [
9
9
  "audit",
10
10
  "catalog",
@@ -73,7 +73,7 @@ var package_default = {
73
73
  "test:src:bin": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin",
74
74
  "test:policy": "vitest run --config vite.config.ts --no-cache --reporter=dot --project policy",
75
75
  "test:config": "vitest run --config vite.config.ts --no-cache --reporter=dot --project config",
76
- "test:guides": "vitest run --config vite.config.ts --no-cache --reporter=dot --project guides",
76
+ "test:guides": "node --experimental-strip-types tests/guides.test.ts",
77
77
  "test:distribution": "vitest run --config vite.config.ts --no-cache --reporter=dot --project distribution",
78
78
  "test:probe": "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe",
79
79
  "test:bench": "vitest bench --config vite.config.ts --no-cache --project probe",
@@ -89,30 +89,29 @@ var package_default = {
89
89
  "prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test && npm run test:distribution -- --mode release"
90
90
  },
91
91
  dependencies: {
92
- "@orkestrel/console": "^0.0.12",
93
- "@orkestrel/contract": "^0.0.16",
94
- "@orkestrel/emitter": "^0.0.9",
95
- "@orkestrel/markdown": "^0.0.13",
96
- "@orkestrel/process": "^0.0.10",
97
- "@orkestrel/template": "^0.0.6"
92
+ "@orkestrel/console": "^0.0.13",
93
+ "@orkestrel/contract": "^0.0.17",
94
+ "@orkestrel/emitter": "^0.0.10",
95
+ "@orkestrel/markdown": "^0.0.14",
96
+ "@orkestrel/process": "^0.0.11",
97
+ "@orkestrel/template": "^0.0.7"
98
98
  },
99
99
  devDependencies: {
100
100
  "@microsoft/api-extractor": "^7.59.0",
101
- "@orkestrel/guide": "^0.0.17",
102
- "@orkestrel/html": "^0.0.8",
103
- "@orkestrel/probe": "^0.0.12",
104
- "@orkestrel/test": "^0.0.13",
105
- "@types/node": "^26.4.0",
101
+ "@orkestrel/guide": "^0.0.18",
102
+ "@orkestrel/html": "^0.0.9",
103
+ "@orkestrel/probe": "^0.0.13",
104
+ "@orkestrel/test": "^0.0.14",
105
+ "@types/node": "^26.5.0",
106
106
  "@vitest/browser-playwright": "^4.1.11",
107
- "oxfmt": "^0.65.0",
108
- "oxlint": "^1.80.0",
109
- "playwright": "^1.62.1",
107
+ "oxfmt": "^0.67.0",
108
+ "oxlint": "^1.82.0",
109
+ "playwright": "^1.63.0",
110
110
  "typescript": "^6.0.3",
111
111
  "vite": "^8.2.2",
112
- "vite-plugin-dts": "^5.0.3",
113
112
  "vitest": "^4.1.11"
114
113
  },
115
- engines: { "node": ">=22.12.0" }
114
+ engines: { "node": ">=22.18.0" }
116
115
  };
117
116
  //#endregion
118
117
  //#region src/core/constants.ts
@@ -212,10 +211,11 @@ var BIN_ENTRY_PATH = "src/bin/main.ts";
212
211
  * @remarks
213
212
  * These are the files the fleet shares verbatim, and each target holds a copy
214
213
  * of the paths it selects: the licence, the harness permission file, the
215
- * session-start hooks, the shared policy register, the shared policy proof,
216
- * the shared policy plugin, the shared configuration leaf and its proof, the
217
- * byte-identical root dotfiles, and the guide mirrors a generated workspace
218
- * starts from. A directory entry vendors everything beneath it.
214
+ * session-start hooks, the shared policy
215
+ * register, the shared policy proof, the shared policy plugin, the shared
216
+ * configuration leaf and its proof, the byte-identical root dotfiles, and the
217
+ * guide mirrors a generated workspace starts from. A directory entry vendors
218
+ * everything beneath it.
219
219
  *
220
220
  * A plan carries the subset its target selects, which is why the list is a
221
221
  * candidate set rather than a plan: a workspace never mirrors its own guide.
@@ -224,16 +224,13 @@ var BIN_ENTRY_PATH = "src/bin/main.ts";
224
224
  * its rules, its skills, its agent roles, its bench configuration, and its MCP
225
225
  * registrations from {@link CANON_PATHS} inside the installed package, so no
226
226
  * file scaffold leaves in a target names a path the target does not hold.
227
- * `nameToHostArtifacts` appends {@link CATALOG_AGENT_PATH} to what this list
227
+ * `blueprintToHostArtifacts` appends {@link CATALOG_AGENT_PATH} to what this list
228
228
  * selects, which is what keeps the list itself disjoint from the canon.
229
229
  */
230
230
  var HOST_PATHS = Object.freeze([
231
231
  "LICENSE",
232
232
  ".claude/settings.json",
233
- "scripts/deps.sh",
234
- "scripts/cursor.sh",
235
- "scripts/codex.sh",
236
- "scripts/ollama.sh",
233
+ "scripts",
237
234
  "tests/setupPolicy.ts",
238
235
  "tests/policy.test.ts",
239
236
  "tests/config.test.ts",
@@ -272,7 +269,7 @@ var HOST_PATHS = Object.freeze([
272
269
  *
273
270
  * The plan claims paths inside the canon deliberately, and each has a reason.
274
271
  * `blueprintToDocumentArtifacts` claims `AGENTS.md` and `CLAUDE.md` as this
275
- * package's own template pointers. `nameToHostArtifacts` claims
272
+ * package's own template pointers. `blueprintToHostArtifacts` claims
276
273
  * {@link CATALOG_AGENT_PATH}, because the catalog verb refuses a target that
277
274
  * lacks the file and repair restores its absence.
278
275
  *
@@ -346,19 +343,19 @@ var ORCHESTRATION_PATH_PREFIXES = Object.freeze([
346
343
  "scripts/"
347
344
  ]);
348
345
  /**
349
- * Lists the exact root filenames that wire an agent bench rather than the toolchain, frozen.
346
+ * Lists the exact root paths that wire an agent bench or own an orchestration directory, frozen.
350
347
  *
351
348
  * @remarks
352
- * `.mcp.json` registers MCP servers for the harness. It sits among the root
353
- * dotfiles but governs agents, so it groups with the harness bridges.
349
+ * `.mcp.json` registers MCP servers for the harness. `scripts` is the owned
350
+ * directory whose members wire the development environment.
354
351
  */
355
- var ORCHESTRATION_PATH_NAMES = Object.freeze([".mcp.json"]);
352
+ var ORCHESTRATION_PATH_NAMES = Object.freeze([".mcp.json", "scripts"]);
356
353
  /**
357
354
  * Names the agent file whose marker-bounded package table the catalog verb alone owns.
358
355
  *
359
356
  * @remarks
360
357
  * A plan claims it at a canon path, because the catalog verb refuses a target
361
- * that lacks the file. `nameToHostArtifacts` appends it to the vendored
358
+ * that lacks the file. `blueprintToHostArtifacts` appends it to the vendored
362
359
  * selection, and it reaches a release through the `.claude/agents` directory in
363
360
  * {@link CANON_PATHS} rather than through {@link HOST_PATHS}, which is what
364
361
  * keeps the two lists disjoint.
@@ -386,11 +383,11 @@ var CATALOG_OPENING_MARKER = "<!-- orkestrel:catalog -->";
386
383
  * refused rather than rewritten.
387
384
  */
388
385
  var CATALOG_CLOSING_MARKER = "<!-- /orkestrel:catalog -->";
389
- /** Names the provisioner skeleton a workspace with declared service vendors is given once. */
386
+ /** Names the inventory skeleton a workspace with declared service vendors is given once. */
390
387
  var SERVICE_SCRIPT_PATH = "scripts/service.sh";
391
388
  /** Names the shared Vitest global-setup module whose presence makes a workspace `global`. */
392
389
  var GLOBAL_SETUP_PATH = "tests/setupGlobal.ts";
393
- /** Names the guide-parity proof whose presence selects the planned `guides` project. */
390
+ /** Names the package-owned guide-parity entry used by `test:guides` and to select the `guides` project. */
394
391
  var GUIDES_TEST_PATH = "tests/guides.test.ts";
395
392
  /** Names the generated packed-package proof every publishing workspace is planned at. */
396
393
  var DISTRIBUTION_TEST_PATH = "tests/distribution.test.ts";
@@ -529,11 +526,29 @@ var MAX_MANIFEST_BYTES = 1048576;
529
526
  /** Caps the bytes retained across one whole plan or audit. */
530
527
  var MAX_TOTAL_ARTIFACT_BYTES = 104857600;
531
528
  /** Names the oldest Node version the generated toolchain supports. */
532
- var MINIMUM_NODE_VERSION = "22.12.0";
529
+ var MINIMUM_NODE_VERSION = "22.18.0";
530
+ /** Names the oldest npm version the generated toolchain supports. */
531
+ var MINIMUM_NPM_VERSION = "11.6.0";
533
532
  /** Names the version a workspace starts at. */
534
533
  var DEFAULT_VERSION = "0.0.1";
535
534
  /** Names the `engines.node` range a workspace starts with. */
536
535
  var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
536
+ /**
537
+ * Holds the `devEngines` record every generated manifest carries.
538
+ *
539
+ * @remarks
540
+ * Every generated manifest names npm at the {@link MINIMUM_NPM_VERSION} floor with the `onFail`
541
+ * key set to the `error` value, and no blueprint field varies that record. An npm at 10.9.0 or
542
+ * later reads the `devEngines` record. Such an npm earlier than the floor refuses an install in a
543
+ * generated workspace rather than resolving its dependency graph.
544
+ * The neighbouring `DEFAULT_ENGINES` constant is the Node range, and a blueprint's `engines`
545
+ * field does replace that one.
546
+ */
547
+ var WORKSPACE_DEV_ENGINES = Object.freeze({ packageManager: Object.freeze({
548
+ name: "npm",
549
+ version: `>=${MINIMUM_NPM_VERSION}`,
550
+ onFail: "error"
551
+ }) });
537
552
  /** Holds the tooling versions scaffold and every generated workspace share. */
538
553
  var BASE_DEV_DEPENDENCIES = Object.freeze({
539
554
  "@orkestrel/guide": package_default.devDependencies["@orkestrel/guide"],
@@ -548,13 +563,13 @@ var BASE_DEV_DEPENDENCIES = Object.freeze({
548
563
  vitest: package_default.devDependencies.vitest
549
564
  });
550
565
  /**
551
- * Lists the development dependencies that emit declarations for published source or an
552
- * executable.
566
+ * Lists the development dependencies that roll declarations up for published source.
567
+ *
568
+ * @remarks
569
+ * The toolchain runs the compiler it already installs as a command, emitting one declaration per
570
+ * module, and the extractor rolls that emit into the single file each published face ships.
553
571
  */
554
- var DECLARATION_DEV_DEPENDENCIES = Object.freeze({
555
- "@microsoft/api-extractor": package_default.devDependencies["@microsoft/api-extractor"],
556
- "vite-plugin-dts": package_default.devDependencies["vite-plugin-dts"]
557
- });
572
+ var DECLARATION_DEV_DEPENDENCIES = Object.freeze({ "@microsoft/api-extractor": package_default.devDependencies["@microsoft/api-extractor"] });
558
573
  /** Lists the development dependencies a published browser `src` environment adds. */
559
574
  var SOURCE_BROWSER_DEV_DEPENDENCIES = Object.freeze({
560
575
  "@vitest/browser-playwright": package_default.devDependencies["@vitest/browser-playwright"],
@@ -895,9 +910,10 @@ export function appBrowser(): UserConfig {
895
910
  setupFiles: ['./tests/setup.ts'],
896
911
  environment: 'node',
897
912
  browser: { enabled: false },
898
- // A config test validates every target wrapper and runs the real linter twice with
899
- // 15-second child caps, so this budget clears both caps and reports their diagnostics.
900
- testTimeout: 45_000,
913
+ // A config test validates every target wrapper, spawns the real linter twice under
914
+ // 15-second child caps, and rolls one face up through the compiler and the extractor it
915
+ // spawns, so this budget clears the capped pair with room for a contended host.
916
+ testTimeout: 60_000,
901
917
  },
902
918
  })
903
919
  `,
@@ -937,9 +953,9 @@ export const conformance = (): UserConfig => ({
937
953
  },
938
954
  })
939
955
  `,
940
- service: `// The live external services this package drives. It starts nothing itself:
941
- // \`scripts/service.sh\` provisions, \`tests/setupService.ts\` proves readiness, and
942
- // the project stays out of \`npm test\` because a real service answers it.
956
+ service: `// The caller prepares the live external services before this project.
957
+ // \`tests/setupService.ts\` verifies readiness, and the project stays out of \`npm test\`
958
+ // because a real service answers it.
943
959
  export const service = (): UserConfig => ({
944
960
  resolve,
945
961
  test: {
@@ -1123,8 +1139,7 @@ export const probe = (): UserConfig => ({
1123
1139
  vites: Object.freeze({
1124
1140
  src: Object.freeze({
1125
1141
  core: `import { defineConfig, mergeConfig } from 'vite'
1126
- import dts from 'vite-plugin-dts'
1127
- import { environmentBoundary, outputBoundary } from '../helpers.js'
1142
+ import { declarationRollup, environmentBoundary, outputBoundary } from '../helpers.js'
1128
1143
  import { peers, srcCore, resolveWorkspacePath } from '../../vite.config.ts'
1129
1144
 
1130
1145
  export default defineConfig(
@@ -1133,17 +1148,9 @@ export default defineConfig(
1133
1148
  plugins: [
1134
1149
  outputBoundary('dist/src/core'),
1135
1150
  environmentBoundary('src/core'),
1136
- dts({
1137
- tsconfigPath: resolveWorkspacePath('configs/src/tsconfig.core.json'),
1138
- bundleTypes: {
1139
- extractorConfig: {
1140
- compiler: {
1141
- overrideTsconfig: {
1142
- compilerOptions: { types: ['node'] },
1143
- },
1144
- },
1145
- },
1146
- },
1151
+ declarationRollup({
1152
+ project: resolveWorkspacePath('configs/src/tsconfig.core.json'),
1153
+ types: ['node'],
1147
1154
  }),
1148
1155
  ],
1149
1156
  build: {
@@ -1164,49 +1171,34 @@ export default defineConfig(
1164
1171
  )
1165
1172
  `,
1166
1173
  browser: `import { defineConfig, mergeConfig } from 'vite'
1167
- import dts from 'vite-plugin-dts'
1174
+ import { declarationRollup, rewriteCoreSpecifier } from '../helpers.js'
1168
1175
  import { srcBrowser, resolveWorkspacePath } from '../../vite.config.ts'
1169
1176
 
1170
- // vite-plugin-dts rolls this face into one declaration, and the roll-up reaches
1171
- // src/core through a relative source path the tarball does not carry. The path
1172
- // keeps each source module's own depth, so a module in a browser subfolder emits
1173
- // one that leaves dist/src entirely. The following rewrite externalizes core
1174
- // through the package's own published root export, on the final roll-up only.
1177
+ // The roll-up reaches src/core through a specifier the tarball does not carry, so the rewrite
1178
+ // externalizes core through the package's own published root export, on the final roll-up alone.
1175
1179
  export default defineConfig(
1176
1180
  mergeConfig(srcBrowser(), {
1177
1181
  plugins: [
1178
- dts({
1179
- tsconfigPath: resolveWorkspacePath('configs/src/tsconfig.browser.json'),
1180
- bundleTypes: true,
1181
- beforeWriteFile: (path, content) => ({
1182
- content: /[\\\\/]dist[\\\\/]src[\\\\/]browser[\\\\/]index\\.d\\.ts$/.test(path)
1183
- {{replacement}}
1184
- : content,
1185
- }),
1182
+ declarationRollup({
1183
+ project: resolveWorkspacePath('configs/src/tsconfig.browser.json'),
1184
+ rewrite: rewriteCoreSpecifier,
1186
1185
  }),
1187
1186
  ],
1188
1187
  }),
1189
1188
  )
1190
1189
  `,
1191
1190
  server: `import { defineConfig, mergeConfig } from 'vite'
1192
- import dts from 'vite-plugin-dts'
1191
+ import { declarationRollup, rewriteCoreSpecifier } from '../helpers.js'
1193
1192
  import { srcServer, resolveWorkspacePath } from '../../vite.config.ts'
1194
1193
 
1195
- // vite-plugin-dts rolls this face into one declaration, and the roll-up reaches
1196
- // src/core through a relative source path the tarball does not carry. The
1197
- // following rewrite externalizes core through the package's own published root
1198
- // export, on the final roll-up only.
1194
+ // The roll-up reaches src/core through a specifier the tarball does not carry, so the rewrite
1195
+ // externalizes core through the package's own published root export, on the final roll-up alone.
1199
1196
  export default defineConfig(
1200
1197
  mergeConfig(srcServer(), {
1201
1198
  plugins: [
1202
- dts({
1203
- tsconfigPath: resolveWorkspacePath('configs/src/tsconfig.server.json'),
1204
- bundleTypes: true,
1205
- beforeWriteFile: (path, content) => ({
1206
- content: /[\\\\/]dist[\\\\/]src[\\\\/]server[\\\\/]index\\.d\\.ts$/.test(path)
1207
- {{replacement}}
1208
- : content,
1209
- }),
1199
+ declarationRollup({
1200
+ project: resolveWorkspacePath('configs/src/tsconfig.server.json'),
1201
+ rewrite: rewriteCoreSpecifier,
1210
1202
  }),
1211
1203
  ],
1212
1204
  }),
@@ -1643,14 +1635,20 @@ import {
1643
1635
  statSync,
1644
1636
  writeFileSync,
1645
1637
  } from 'node:fs'
1646
- {{transport}}import { tmpdir } from 'node:os'
1638
+ {{transport}}import { createRequire } from 'node:module'
1639
+ import { tmpdir } from 'node:os'
1647
1640
  import { dirname, join, resolve } from 'node:path'
1648
1641
  import { fileURLToPath } from 'node:url'
1649
- {{launcher}}import ts from 'typescript'
1650
- import { afterAll, describe, expect, it } from 'vitest'
1642
+ {{launcher}}import { afterAll, describe, expect, it } from 'vitest'
1651
1643
 
1652
1644
  const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
1653
1645
  const NPM = process.platform === 'win32' ? 'npm.cmd' : 'npm'
1646
+ // The compiler this workspace installs, run as a command rather than called in
1647
+ // process: the command and its plain-text diagnostics are the same across the
1648
+ // compiler majors this toolchain supports, and its in-process API is not. It is
1649
+ // resolved from the workspace under proof, so a consumer of the packed artifact is
1650
+ // checked by the same compiler that workspace's own \`check\` script runs.
1651
+ const TSC = createRequire(join(ROOT, 'package.json')).resolve('typescript/bin/tsc')
1654
1652
  // Windows needs a shell to launch a \`.cmd\`: Node refuses one directly since the
1655
1653
  // batch-argument hardening, and \`spawnSync\` returns \`EINVAL\` with a null status
1656
1654
  // rather than an exit code a caller can read. Every following argument is a literal or
@@ -1667,6 +1665,12 @@ const RELEASE = import.meta.env.MODE === 'release'
1667
1665
  // Node and the miss is silent.
1668
1666
  const BROWSER_OUTPUT = './dist/src/browser/'
1669
1667
  const ABSENT_SUBPATH = '/no-subpath-is-published-under-this-name'
1668
+ // A compiler diagnostic that says where it is: the path relative to the directory
1669
+ // the compiler ran in, the 1-based line and column, the code, and the message. The
1670
+ // diagnostics are the verdict rather than the exit code, which differs between the
1671
+ // compiler majors this toolchain supports, so a reported line matching nothing here
1672
+ // came from something other than a check of a consumer module.
1673
+ const DIAGNOSTIC_PATTERN = /^(.+?)\\(\\d+,\\d+\\): error TS\\d+: /u
1670
1674
  const PING = ['ping', '--fetch-retries=0', '--fetch-timeout=5000', '--loglevel=silent']
1671
1675
  const ESM_DRIVER = 'drive.mjs'
1672
1676
  const CJS_DRIVER = 'drive.cjs'
@@ -1712,8 +1716,8 @@ const DECLARATION_CONDITIONS = Object.freeze({
1712
1716
 
1713
1717
  interface Resolution {
1714
1718
  readonly label: string
1715
- readonly resolution: ts.ModuleResolutionKind
1716
- readonly module: ts.ModuleKind
1719
+ readonly resolution: string
1720
+ readonly module: string
1717
1721
  readonly conditions: Readonly<Record<Format, readonly string[]>>
1718
1722
  }
1719
1723
 
@@ -1721,51 +1725,61 @@ interface TargetResolution {
1721
1725
  readonly target: string
1722
1726
  }
1723
1727
 
1724
- // Each compile driver carries the conditions TypeScript applies for its resolution
1725
- // and importing format. A \`require\`-only subpath therefore stays in each CommonJS
1726
- // probe that can resolve it.
1728
+ // Each compile driver carries the compiler options its scratch project sets and
1729
+ // the conditions TypeScript applies for that resolution and importing format. A
1730
+ // \`require\`-only subpath therefore stays in each CommonJS probe that can resolve it.
1731
+ // The option values are the spellings the project file takes, so nothing here needs
1732
+ // the compiler's own API to name them.
1727
1733
  const RESOLUTIONS: readonly Resolution[] = [
1728
1734
  {
1729
1735
  label: 'node16',
1730
- resolution: ts.ModuleResolutionKind.Node16,
1731
- module: ts.ModuleKind.Node16,
1736
+ resolution: 'node16',
1737
+ module: 'node16',
1732
1738
  conditions: DECLARATION_CONDITIONS,
1733
1739
  },
1734
1740
  {
1735
1741
  label: 'nodenext',
1736
- resolution: ts.ModuleResolutionKind.NodeNext,
1737
- module: ts.ModuleKind.NodeNext,
1742
+ resolution: 'nodenext',
1743
+ module: 'nodenext',
1738
1744
  conditions: DECLARATION_CONDITIONS,
1739
1745
  },
1740
1746
  {
1741
1747
  label: 'bundler',
1742
- resolution: ts.ModuleResolutionKind.Bundler,
1743
- module: ts.ModuleKind.ESNext,
1748
+ resolution: 'bundler',
1749
+ module: 'esnext',
1744
1750
  conditions: BUNDLER_CONDITIONS,
1745
1751
  },
1746
1752
  ]
1747
1753
 
1754
+ // The driver a bundled consumer reads declarations under. A browser application
1755
+ // compiles through a bundler, so the browser drive answers under this one alone,
1756
+ // and naming it here is what keeps that selection tied to the driver it selects.
1757
+ const BROWSER_DRIVER = RESOLUTIONS.find((candidate) => candidate.label === 'bundler')
1758
+ if (BROWSER_DRIVER === undefined) throw new Error("RESOLUTIONS carries no 'bundler' row")
1759
+
1748
1760
  const FORMATS: ReadonlyArray<readonly [extension: string, format: Format]> = [
1749
1761
  ['ts', 'module'],
1750
1762
  ['cts', 'commonjs'],
1751
1763
  ]
1752
1764
 
1753
1765
  // One published subpath, resolved to what this proof can drive: the specifier a
1754
- // consumer writes, the declarations its consumer formats name, whether its target
1755
- // is a browser bundle, and whether it answers \`import\` and \`require\` at all.
1766
+ // consumer writes, whether the declarations its consumer formats resolve at all,
1767
+ // whether the exports map answers the browser condition with a target of its own,
1768
+ // whether it answers \`import\` and \`require\` at all, and whether the target that
1769
+ // \`require\` answers with is one that a CommonJS consumer loads.
1756
1770
  interface Entry {
1757
1771
  readonly subpath: string
1758
1772
  readonly specifier: string
1759
1773
  readonly mapping: unknown
1760
1774
  readonly declaration: {
1761
- readonly module: string | undefined
1762
- readonly commonjs: string | undefined
1763
- readonly browser: string | undefined
1775
+ readonly importable: boolean
1776
+ readonly requirable: boolean
1777
+ readonly browsable: boolean
1764
1778
  }
1765
- readonly browser: boolean
1766
- readonly module: boolean
1767
- readonly commonjs: boolean
1768
- readonly required: boolean
1779
+ readonly browsable: boolean
1780
+ readonly importable: boolean
1781
+ readonly requirable: boolean
1782
+ readonly loadable: boolean
1769
1783
  }
1770
1784
 
1771
1785
  // The installed tree every claim is read from. Every subpath the exports map names
@@ -2018,7 +2032,14 @@ function isDeclaration(target: string): boolean {
2018
2032
  // against. Each field uses the conditions of the TypeScript consumer paired with
2019
2033
  // that runtime. A JavaScript target resolves through TypeScript's adjacent
2020
2034
  // declaration substitution rather than standing in for the declaration itself.
2021
- function readDeclaration(entry: unknown, installed: string): Entry['declaration'] {
2035
+ function readDeclaration(
2036
+ entry: unknown,
2037
+ installed: string,
2038
+ ): {
2039
+ readonly module: string | undefined
2040
+ readonly commonjs: string | undefined
2041
+ readonly browser: string | undefined
2042
+ } {
2022
2043
  return {
2023
2044
  module: resolveDeclaration(entry, DECLARATION_CONDITIONS.module, installed),
2024
2045
  commonjs: resolveDeclaration(entry, DECLARATION_CONDITIONS.commonjs, installed),
@@ -2031,72 +2052,137 @@ function selectEntries(entries: readonly Entry[], conditions: readonly string[])
2031
2052
  return entries.filter(
2032
2053
  (entry) =>
2033
2054
  resolveTarget(entry.mapping, conditions) !== undefined &&
2034
- (!conditions.includes('require') || entry.commonjs),
2055
+ (!conditions.includes('require') || entry.loadable),
2056
+ )
2057
+ }
2058
+
2059
+ // The compile drivers whose conditions reach one entry under one importing format.
2060
+ // A driver that resolves no target for that entry compiles nothing, so a consumer
2061
+ // written under it would report a resolution failure this package never made.
2062
+ function selectDrivers(entry: Entry, format: Format): readonly Resolution[] {
2063
+ return RESOLUTIONS.filter(
2064
+ (driver) => selectEntries([entry], driver.conditions[format]).length > 0,
2035
2065
  )
2036
2066
  }
2037
2067
 
2038
- // Require-loadable entries that declare CommonJS support but a typed CommonJS
2039
- // consumer cannot compile against. A default branch resolving under the require
2040
- // condition set makes no CommonJS claim.
2068
+ // Requirable entries that declare CommonJS support but a typed CommonJS consumer
2069
+ // cannot compile against. A default branch resolving under the require condition
2070
+ // set makes no CommonJS claim.
2041
2071
  function selectUntypable(entries: readonly Entry[], installed: string): readonly Entry[] {
2042
2072
  return entries.filter(
2043
2073
  (entry) =>
2044
- entry.required &&
2074
+ entry.requirable &&
2045
2075
  isRecord(entry.mapping) &&
2046
2076
  Object.hasOwn(entry.mapping, 'require') &&
2047
2077
  !declaresCommonJS(entry.mapping, installed),
2048
2078
  )
2049
2079
  }
2050
2080
 
2051
- // The value exports a declaration publishes, read through the compiler's checker
2052
- // over the module symbol rather than off the declaration text. An alias resolves to
2053
- // what it names, so a re-export counts as the thing it re-exports, and a type-only
2054
- // symbol is dropped because no runtime publishes one.
2055
- function readDeclaredExports(declaration: string): readonly string[] {
2056
- const program = ts.createProgram([declaration], {
2057
- module: ts.ModuleKind.ESNext,
2058
- moduleResolution: ts.ModuleResolutionKind.Bundler,
2059
- noEmit: true,
2060
- skipLibCheck: true,
2061
- target: ts.ScriptTarget.ESNext,
2062
- })
2063
- const source = program.getSourceFile(declaration)
2064
- if (source === undefined) throw new Error(\`The declaration \${declaration} was not read\`)
2065
- const checker = program.getTypeChecker()
2066
- const symbol = checker.getSymbolAtLocation(source)
2067
- if (symbol === undefined) throw new Error(\`\${declaration} declares no module symbol\`)
2068
- const values: string[] = []
2069
- for (const exported of checker.getExportsOfModule(symbol)) {
2070
- const direct = (exported.flags & ts.SymbolFlags.Alias) === 0
2071
- const resolved = direct ? exported : checker.getAliasedSymbol(exported)
2072
- if ((resolved.flags & ts.SymbolFlags.Value) !== 0) values.push(exported.getName())
2081
+ // One surface comparison, written as the consumer module that proves it: the
2082
+ // installed entry that consumer imports, the file extension fixing its importing
2083
+ // format, the names a real runtime published off it, and the driver whose scratch
2084
+ // project compiles it.
2085
+ interface Surface {
2086
+ readonly entry: Entry
2087
+ readonly extension: string
2088
+ readonly published: readonly string[]
2089
+ readonly driver: Resolution
2090
+ }
2091
+
2092
+ // A scratch project over named consumer modules, written beside them so their own
2093
+ // resolution reaches the installed package. Nothing is emitted and no ambient types
2094
+ // are pulled in, so what the check reads is the installed declarations alone.
2095
+ function writeProject(
2096
+ stage: Stage,
2097
+ name: string,
2098
+ driver: Resolution,
2099
+ files: readonly string[],
2100
+ ): string {
2101
+ const path = join(stage.consumer, \`tsconfig.\${name}.json\`)
2102
+ const project = {
2103
+ compilerOptions: {
2104
+ module: driver.module,
2105
+ moduleResolution: driver.resolution,
2106
+ noEmit: true,
2107
+ skipLibCheck: true,
2108
+ strict: true,
2109
+ target: 'esnext',
2110
+ types: [],
2111
+ },
2112
+ files: [...files],
2073
2113
  }
2074
- return [...values].sort()
2114
+ writeFile(path, \`\${JSON.stringify(project, undefined, '\\t')}\\n\`)
2115
+ return path
2075
2116
  }
2076
2117
 
2077
- // The diagnostics a consumer compiling against the installed declarations reports,
2078
- // flattened to their messages so a failure names what the consumer could not do.
2079
- function compileConsumer(
2080
- entry: string,
2081
- resolution: ts.ModuleResolutionKind,
2082
- module: ts.ModuleKind,
2083
- ): readonly string[] {
2084
- const program = ts.createProgram([entry], {
2085
- module,
2086
- moduleResolution: resolution,
2087
- noEmit: true,
2088
- skipLibCheck: true,
2089
- strict: true,
2090
- target: ts.ScriptTarget.ESNext,
2091
- })
2092
- return ts
2093
- .getPreEmitDiagnostics(program)
2094
- .map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, ' '))
2118
+ // The diagnostics the compiler this workspace installs reports for one scratch
2119
+ // project. The compiler runs as a command, so nothing here reaches an API that
2120
+ // moves between its majors, and the located lines it prints are the verdict rather
2121
+ // than the exit code, which moves between them. A line carrying no location, a line
2122
+ // naming the scratch project rather than a consumer module, and anything at all on
2123
+ // the error stream are faults of this proof rather than of the package under proof,
2124
+ // so each is raised where it happens instead of counted against the package.
2125
+ function checkProject(stage: Stage, project: string): readonly string[] {
2126
+ const result = runNode([TSC, '--noEmit', '--pretty', 'false', '-p', project], stage.consumer)
2127
+ const refused = \`\${result.stderr ?? ''}\`.trim()
2128
+ if (refused.length > 0) {
2129
+ throw new Error(\`The consumer compiler wrote \${refused} to its error stream\`)
2130
+ }
2131
+ const reported: string[] = []
2132
+ for (const line of \`\${result.stdout ?? ''}\`.split(/\\r\\n|\\n/u)) {
2133
+ if (line.trim().length === 0) continue
2134
+ const last = reported.at(-1)
2135
+ // An elaborated diagnostic prints its detail on indented lines under its own
2136
+ // first line, so each of those joins the diagnostic it elaborates.
2137
+ if (/^\\s/u.test(line) && last !== undefined) {
2138
+ reported[reported.length - 1] = \`\${last} \${line.trim()}\`
2139
+ continue
2140
+ }
2141
+ const located = DIAGNOSTIC_PATTERN.exec(line)?.[1]
2142
+ if (located === undefined) {
2143
+ throw new Error(\`The consumer compiler reported \${line}, which names no location\`)
2144
+ }
2145
+ if (resolve(stage.consumer, located) === project) {
2146
+ throw new Error(\`The scratch project is itself at fault: \${line}\`)
2147
+ }
2148
+ reported.push(line)
2149
+ }
2150
+ if (reported.length === 0 && result.status !== 0) {
2151
+ throw new Error(\`The consumer compiler refused the project: \${readOutput(result)}\`)
2152
+ }
2153
+ return reported
2154
+ }
2155
+
2156
+ // One installed entry's published names checked against its own declarations by
2157
+ // the compiler this workspace installs, in the direction each divergence surfaces
2158
+ // under. The runtime's key list is written into the consumer as a literal, so the
2159
+ // published side comes from a real process and the declared side from the
2160
+ // declarations that process's package ships, and the two can disagree. A name the
2161
+ // declarations carry and the runtime does not lands on \`declared\`. A name the
2162
+ // runtime carries and the declarations do not, and a name the declarations publish
2163
+ // as a type alone, land on \`surfaced\`: a variable widens into the type
2164
+ // \`declared\` annotates, and only \`surfaced\` reads the literal's own keys back.
2165
+ // Each names the member it is about, so the failure says which export moved.
2166
+ function checkSurface(stage: Stage, surface: Surface): readonly string[] {
2167
+ const slug = surface.entry.subpath.replaceAll(/[^\\w]+/gu, '-')
2168
+ const name = \`surface.\${surface.driver.label}\${slug}.\${surface.extension}\`
2169
+ const module = \`\${name}\`
2170
+ const keys = surface.published.map((key) => \`\${JSON.stringify(key)}: true\`).join(', ')
2171
+ writeFile(
2172
+ join(stage.consumer, module),
2173
+ \`import * as entry from \${JSON.stringify(surface.entry.specifier)}
2174
+ const published = {\${keys.length === 0 ? '' : \` \${keys} \`}} as const
2175
+ const declared: Record<keyof typeof entry, true> = published
2176
+ const surfaced: Record<keyof typeof published, true> = declared
2177
+ \`,
2178
+ )
2179
+ const project = writeProject(stage, name, surface.driver, [\`./\${module}\`])
2180
+ return checkProject(stage, project).map((line) => \`\${surface.driver.label}: \${line}\`)
2095
2181
  }
2096
2182
 
2097
2183
  // One consumer module importing every installed entry, written where its own
2098
2184
  // resolution finds the installed package.
2099
- function writeConsumerProbe(stage: Stage, path: string, specifiers: readonly string[]): string {
2185
+ function writeConsumerProbe(stage: Stage, path: string, specifiers: readonly string[]): void {
2100
2186
  const names: string[] = []
2101
2187
  const bindings: string[] = []
2102
2188
  for (const [index, specifier] of specifiers.entries()) {
@@ -2104,9 +2190,8 @@ function writeConsumerProbe(stage: Stage, path: string, specifiers: readonly str
2104
2190
  names.push(binding)
2105
2191
  bindings.push(\`import * as \${binding} from \${JSON.stringify(specifier)}\`)
2106
2192
  }
2107
- const target = join(stage.consumer, path)
2108
- writeFile(target, \`\${bindings.join('\\n')}\\nexport const surface = [\${names.join(', ')}]\\n\`)
2109
- return target
2193
+ const source = \`\${bindings.join('\\n')}\\nexport const surface = [\${names.join(', ')}]\\n\`
2194
+ writeFile(join(stage.consumer, path), source)
2110
2195
  }
2111
2196
 
2112
2197
  // The runtime key set a real process reads off one installed entry under one
@@ -2176,27 +2261,26 @@ function buildStage(): Stage {
2176
2261
  else excluded.push(subpath)
2177
2262
  continue
2178
2263
  }
2179
- const imported = resolveTarget(entry, RUNTIME_CONDITIONS.module)
2180
- const requiredTarget = resolveTarget(entry, RUNTIME_CONDITIONS.commonjs)
2264
+ const importTarget = resolveTarget(entry, RUNTIME_CONDITIONS.module)
2265
+ const requireTarget = resolveTarget(entry, RUNTIME_CONDITIONS.commonjs)
2181
2266
  const browserTarget = resolveTarget(entry, RUNTIME_CONDITIONS.browser)
2182
- const browser = resolvesBrowser(entry)
2183
- const required = requiredTarget !== undefined && !(browser && requiredTarget === browserTarget)
2184
- const commonjs = required && resolvesCommonJS(entry, installed)
2267
+ const browsable = resolvesBrowser(entry)
2268
+ const shadowed = browsable && requireTarget === browserTarget
2269
+ const requirable = requireTarget !== undefined && !shadowed
2270
+ const loadable = requirable && resolvesCommonJS(entry, installed)
2185
2271
  entries.push({
2186
2272
  subpath,
2187
2273
  specifier: subpath === '.' ? name : \`\${name}\${subpath.slice(1)}\`,
2188
2274
  mapping: entry,
2189
2275
  declaration: {
2190
- module: declaration.module === undefined ? undefined : join(installed, declaration.module),
2191
- commonjs:
2192
- declaration.commonjs === undefined ? undefined : join(installed, declaration.commonjs),
2193
- browser:
2194
- declaration.browser === undefined ? undefined : join(installed, declaration.browser),
2276
+ importable: declaration.module !== undefined,
2277
+ requirable: declaration.commonjs !== undefined,
2278
+ browsable: declaration.browser !== undefined,
2195
2279
  },
2196
- browser,
2197
- module: imported !== undefined && !(browser && imported === browserTarget),
2198
- commonjs,
2199
- required,
2280
+ browsable,
2281
+ importable: importTarget !== undefined && !(browsable && importTarget === browserTarget),
2282
+ requirable,
2283
+ loadable,
2200
2284
  })
2201
2285
  }
2202
2286
  return { consumer, installed, archives, entries, subpaths, undeclared, excluded, targets }
@@ -2347,7 +2431,7 @@ describe('installed package consumer', () => {
2347
2431
  // loads it. Each later drive retires itself for that entry, so this assertion names
2348
2432
  // the subpath rather than counting it as driven.
2349
2433
  const unreachable = stage.entries.filter(
2350
- (entry) => !entry.module && !entry.required && !entry.browser,
2434
+ (entry) => !entry.importable && !entry.requirable && !entry.browsable,
2351
2435
  )
2352
2436
  expect(unreachable.map((entry) => entry.subpath)).toStrictEqual([])
2353
2437
  const untypable = selectUntypable(stage.entries, stage.installed)
@@ -2376,16 +2460,18 @@ describe('installed package consumer', () => {
2376
2460
  for (const [extension, format] of FORMATS) {
2377
2461
  const written = selectEntries(stage.entries, driver.conditions[format])
2378
2462
  if (written.length === 0) continue
2463
+ const label = \`\${driver.label}.\${extension}\`
2464
+ const probe = \`probe.\${label}\`
2379
2465
  const specifiers = written.map((entry) => entry.specifier)
2380
- const probe = writeConsumerProbe(stage, \`probe.\${driver.label}.\${extension}\`, specifiers)
2381
- for (const message of compileConsumer(probe, driver.resolution, driver.module)) {
2382
- reported.push(\`\${driver.label}.\${extension}: \${message}\`)
2383
- }
2384
- const absent = [\`\${name}\${ABSENT_SUBPATH}\`]
2385
- const control = writeConsumerProbe(stage, \`control.\${driver.label}.\${extension}\`, absent)
2386
- if (compileConsumer(control, driver.resolution, driver.module).length === 0) {
2387
- silent.push(\`\${driver.label}.\${extension}\`)
2466
+ writeConsumerProbe(stage, probe, specifiers)
2467
+ const project = writeProject(stage, probe, driver, [\`./\${probe}\`])
2468
+ for (const message of checkProject(stage, project)) {
2469
+ reported.push(\`\${label}: \${message}\`)
2388
2470
  }
2471
+ const control = \`control.\${label}\`
2472
+ writeConsumerProbe(stage, control, [\`\${name}\${ABSENT_SUBPATH}\`])
2473
+ const refused = writeProject(stage, control, driver, [\`./\${control}\`])
2474
+ if (checkProject(stage, refused).length === 0) silent.push(label)
2389
2475
  }
2390
2476
  }
2391
2477
  expect(reported).toStrictEqual([])
@@ -2395,27 +2481,44 @@ describe('installed package consumer', () => {
2395
2481
 
2396
2482
  for (const entry of STAGE?.entries ?? []) {
2397
2483
  describe(\`installed entry \${entry.subpath}\`, () => {
2398
- it.runIf(entry.module)(
2484
+ it.runIf(entry.importable)(
2399
2485
  'publishes what it declares to a Node import, and no more',
2400
2486
  (context) => {
2401
- const declaration = entry.declaration.module
2402
- if (declaration === undefined) {
2487
+ const stage = requireStage(context)
2488
+ // The exports-map walk resolved a declaration a typed importer reads, so an
2489
+ // entry reaching this drive without one is reported for that rather than for
2490
+ // what a consumer of a missing declaration goes on to say.
2491
+ if (!entry.declaration.importable) {
2403
2492
  throw new Error(\`\${entry.subpath} publishes no import declaration\`)
2404
2493
  }
2405
- const published = driveRuntime(requireStage(context), entry.specifier, ESM_DRIVER)
2406
- expect(published).toStrictEqual(readDeclaredExports(declaration))
2494
+ const published = driveRuntime(stage, entry.specifier, ESM_DRIVER)
2495
+ const drivers = selectDrivers(entry, 'module')
2496
+ expect(drivers).not.toStrictEqual([])
2497
+ const reported = drivers.flatMap((driver) =>
2498
+ checkSurface(stage, { entry, extension: 'ts', published, driver }),
2499
+ )
2500
+ expect(reported).toStrictEqual([])
2407
2501
  },
2408
2502
  )
2409
2503
 
2410
- it.runIf(entry.required)(
2504
+ it.runIf(entry.requirable)(
2411
2505
  'publishes what it declares to a Node require, and no more',
2412
2506
  (context) => {
2413
- const declaration = entry.declaration.commonjs
2414
- if (declaration === undefined) {
2507
+ const stage = requireStage(context)
2508
+ if (!entry.declaration.requirable) {
2415
2509
  throw new Error(\`\${entry.subpath} publishes no require declaration\`)
2416
2510
  }
2417
- const published = driveRuntime(requireStage(context), entry.specifier, CJS_DRIVER)
2418
- expect(published).toStrictEqual(readDeclaredExports(declaration))
2511
+ const published = driveRuntime(stage, entry.specifier, CJS_DRIVER)
2512
+ // A subpath whose \`require\` resolves to a module that no typed CommonJS
2513
+ // consumer can compile against carries no declared side to compare here, and
2514
+ // whether it may publish one at all is the untypable set's question rather
2515
+ // than this drive's. The preceding runtime drive ran either way.
2516
+ const drivers = selectDrivers(entry, 'commonjs')
2517
+ expect(drivers).not.toStrictEqual([])
2518
+ const reported = drivers.flatMap((driver) =>
2519
+ checkSurface(stage, { entry, extension: 'cts', published, driver }),
2520
+ )
2521
+ expect(reported).toStrictEqual([])
2419
2522
  },
2420
2523
  )
2421
2524
  {{drive}} })
@@ -2528,12 +2631,11 @@ async function readBrowserExports(browser: Browser, bundle: string): Promise<rea
2528
2631
  }
2529
2632
  `,
2530
2633
  drive: `
2531
- it.runIf(entry.browser)(
2634
+ it.runIf(entry.browsable)(
2532
2635
  'publishes what it declares to a real browser, and no more [requires a browser]',
2533
2636
  async (context) => {
2534
2637
  const stage = requireStage(context)
2535
- const declaration = entry.declaration.browser
2536
- if (declaration === undefined) {
2638
+ if (!entry.declaration.browsable) {
2537
2639
  throw new Error(\`\${entry.subpath} publishes no browser declaration\`)
2538
2640
  }
2539
2641
  const options = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)
@@ -2544,9 +2646,16 @@ async function readBrowserExports(browser: Browser, bundle: string): Promise<rea
2544
2646
  })
2545
2647
  try {
2546
2648
  const bundle = await bundleEntry(stage, entry)
2547
- expect(await readBrowserExports(browser, bundle)).toStrictEqual(
2548
- readDeclaredExports(declaration),
2549
- )
2649
+ const published = await readBrowserExports(browser, bundle)
2650
+ // A browser consumer reads the installed declarations through a bundler, so
2651
+ // that is the one driver this face answers under.
2652
+ const reported = checkSurface(stage, {
2653
+ entry,
2654
+ extension: 'ts',
2655
+ published,
2656
+ driver: BROWSER_DRIVER,
2657
+ })
2658
+ expect(reported).toStrictEqual([])
2550
2659
  } finally {
2551
2660
  await browser.close()
2552
2661
  }
@@ -2569,7 +2678,7 @@ async function readBrowserExports(browser: Browser, bundle: string): Promise<rea
2569
2678
  // file and runs the \`repair\` verb, which writes the variant carrying that branch.
2570
2679
  it('publishes no browser face this proof cannot drive [requires the registry]', (context) => {
2571
2680
  const stage = requireStage(context)
2572
- const faces = stage.entries.filter((entry) => entry.browser)
2681
+ const faces = stage.entries.filter((entry) => entry.browsable)
2573
2682
  expect(faces.map((entry) => entry.subpath)).toStrictEqual([])
2574
2683
  })
2575
2684
  `
@@ -2684,12 +2793,12 @@ printf '%s\\n' \\
2684
2793
  *
2685
2794
  * @example
2686
2795
  * ```ts
2687
- * import { ScaffoldError, isScaffoldError } from '@orkestrel/scaffold'
2796
+ * import { isScaffoldError, ScaffoldError } from '@orkestrel/scaffold'
2688
2797
  *
2689
2798
  * try {
2690
- * throw new ScaffoldError('INVALID', 'Blueprint is not an exact record')
2799
+ * throw new ScaffoldError('TARGET', 'The target carries no readable manifest.')
2691
2800
  * } catch (error) {
2692
- * if (isScaffoldError(error)) error.code // 'INVALID'
2801
+ * if (isScaffoldError(error)) error.code // 'TARGET'
2693
2802
  * }
2694
2803
  * ```
2695
2804
  */
@@ -3134,7 +3243,8 @@ var isCatalogEntry = unionOf(recordOf({
3134
3243
  name: isDependencyName,
3135
3244
  lookup: literalOf("found"),
3136
3245
  version: isString,
3137
- dependencies: andOf(isCollection, arrayOf(isDependency))
3246
+ dependencies: andOf(isCollection, arrayOf(isDependency)),
3247
+ peers: andOf(isCollection, arrayOf(isDependency))
3138
3248
  }), recordOf({
3139
3249
  name: isDependencyName,
3140
3250
  lookup: literalOf("missing", "unmatched", "failed"),
@@ -3520,7 +3630,7 @@ function isCanonPath(path) {
3520
3630
  return CANON_PATHS.some((canon) => path === canon || path.startsWith(`${canon}/`));
3521
3631
  }
3522
3632
  /**
3523
- * Checks whether a target's present bytes at a path are owned by another surface.
3633
+ * Checks whether another surface owns a target's present bytes at a path.
3524
3634
  *
3525
3635
  * @param path - The target-relative path to test.
3526
3636
  * @returns True if the path is a {@link WORKSPACE_OWNED_PATHS} member or a
@@ -3697,46 +3807,6 @@ function matchesPrintWidth(line) {
3697
3807
  return line.replaceAll(" ", " ".repeat(2)).length <= 100;
3698
3808
  }
3699
3809
  /**
3700
- * Derives the declaration rewrite a published face's `beforeWriteFile` applies.
3701
- *
3702
- * @param name - The workspace's own bare package name.
3703
- * @returns The ternary consequent an emitted `vite.{browser,server}.config.ts`
3704
- * fills its `{{replacement}}` span with, indented for that span.
3705
- *
3706
- * @remarks
3707
- * `vite-plugin-dts` rolls a face into one declaration and keeps each source
3708
- * module's own relative depth, so a nested module emits a path that escapes
3709
- * `dist/src` and a flat one resolves only by luck. Both faces rewrite the same
3710
- * relative core path to the package's published root export, so the branch is
3711
- * derived once here. The extension alternation is what the permitted import
3712
- * spellings produce: an `@src/core` alias resolves to the core source module and
3713
- * prints `.ts`, while a relative import prints the `.js` specifier it was
3714
- * written with. The formatter keeps the call on one line only while the line it
3715
- * prints measures inside the vendored width, and the workspace name is what
3716
- * varies, so the shape is chosen by measuring the candidate: a tab prints as the
3717
- * vendored two columns, and the gate admits a name long enough to push the
3718
- * joined call past 100.
3719
- *
3720
- * @example
3721
- * ```ts
3722
- * import { nameToRewrite } from '@orkestrel/scaffold'
3723
- *
3724
- * nameToRewrite('router').includes("'@orkestrel/router'") // true
3725
- * ```
3726
- */
3727
- function nameToRewrite(name) {
3728
- const specifier = serializeTypeScriptString(`@orkestrel/${name}`);
3729
- const pattern = "/(?:\\.\\.\\/)+core\\/index\\.[jt]s/g";
3730
- const joined = `\t\t\t\t\t\t? content.replaceAll(${pattern}, ${specifier})`;
3731
- if (matchesPrintWidth(joined)) return joined;
3732
- return [
3733
- " ? content.replaceAll(",
3734
- `\t\t\t\t\t\t\t\t${pattern},`,
3735
- `\t\t\t\t\t\t\t\t${specifier},`,
3736
- " )"
3737
- ].join("\n");
3738
- }
3739
- /**
3740
3810
  * Selects the single published environment a package root points at.
3741
3811
  *
3742
3812
  * @param src - The declared published environments.
@@ -3992,9 +4062,11 @@ function matchesDriftReachability(ownership, finding) {
3992
4062
  * @remarks
3993
4063
  * A layer is a deterministic function of the catalog's own edges, so it is
3994
4064
  * computed here rather than stored on a row that could disagree with them.
3995
- * Only RUNTIME edges between catalogued packages count: a development
4065
+ * Only RUNTIME and PEER edges between catalogued packages count: a development
3996
4066
  * dependency reaches no consumer, so it constrains nothing about publish order,
3997
- * and an edge leaving the fleet is a package this catalog does not publish.
4067
+ * and an edge leaving the fleet is a package this catalog does not publish. A
4068
+ * peer edge counts like a runtime edge, because a caret peer range at `0.0.x`
4069
+ * names one exact release the dependent cannot publish ahead of.
3998
4070
  *
3999
4071
  * The order matters because these packages are `0.0.x`, where a caret pins one
4000
4072
  * exact release. Publishing a dependent before its dependency leaves the
@@ -4005,11 +4077,12 @@ function matchesDriftReachability(ownership, finding) {
4005
4077
  * placed in an order that would be wrong. An absent name is the report: compare
4006
4078
  * the returned names against the catalog to find one.
4007
4079
  *
4008
- * @example
4080
+ * @example Fleet catalog
4009
4081
  * ```ts
4010
4082
  * import { catalogToLayers } from '@orkestrel/scaffold'
4011
4083
  *
4012
- * catalogToLayers(entries)[0] // the names that depend on nothing in the fleet
4084
+ * const layers = catalogToLayers(entries)
4085
+ * layers[0] // the names that depend on nothing else in the fleet
4013
4086
  * ```
4014
4087
  */
4015
4088
  function catalogToLayers(entries) {
@@ -4017,7 +4090,7 @@ function catalogToLayers(entries) {
4017
4090
  const pending = /* @__PURE__ */ new Map();
4018
4091
  for (const entry of entries) {
4019
4092
  if (entry.lookup !== "found") continue;
4020
- const edges = entry.dependencies.map((dependency) => dependency.name);
4093
+ const edges = [...entry.dependencies, ...entry.peers].map((dependency) => dependency.name);
4021
4094
  pending.set(entry.name, new Set(edges.filter((name) => published.has(name))));
4022
4095
  }
4023
4096
  const layers = [];
@@ -4231,9 +4304,9 @@ function matchesRange(range, latest) {
4231
4304
  * ```ts
4232
4305
  * import { matchesEngines } from '@orkestrel/scaffold'
4233
4306
  *
4234
- * matchesEngines('>=22.12.0') // true
4307
+ * matchesEngines('>=22.18.0') // true
4235
4308
  * matchesEngines('>=20.0.0') // false
4236
- * matchesEngines('22.12.0') // false
4309
+ * matchesEngines('22.18.0') // false
4237
4310
  * ```
4238
4311
  */
4239
4312
  function matchesEngines(engines) {
@@ -4594,7 +4667,7 @@ function blueprintToScripts(blueprint) {
4594
4667
  scripts["test:policy"] = `${vitest} --project policy`;
4595
4668
  scripts["test:config"] = `${vitest} --project config`;
4596
4669
  if (blueprint.setup) scripts["test:setup"] = `${vitest} --project setup`;
4597
- if (blueprint.guides) scripts["test:guides"] = `${vitest} --project guides`;
4670
+ if (blueprint.guides) scripts["test:guides"] = `node --experimental-strip-types ${GUIDES_TEST_PATH}`;
4598
4671
  if (blueprint.conformance) scripts["test:conformance"] = `${vitest} --project conformance`;
4599
4672
  scripts["test:probe"] = "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe";
4600
4673
  scripts["test:bench"] = "vitest bench --config vite.config.ts --no-cache --project probe";
@@ -4648,13 +4721,16 @@ function blueprintToScripts(blueprint) {
4648
4721
  *
4649
4722
  * @remarks
4650
4723
  * Every direct `test:<project>` script is writable, together with the probe and
4651
- * benchmark workbench scripts. Publishing adds the pack and publication
4652
- * lifecycle scripts. Aggregate test scripts and maintainer-owned gate chains
4653
- * stay outside the region.
4724
+ * benchmark workbench scripts. A workspace carrying guides adds `test:guides`,
4725
+ * whose package-owned entry runs the guides project and handles explicit parity
4726
+ * rewrites. Publishing adds the pack and publication lifecycle scripts.
4727
+ * Aggregate test scripts and
4728
+ * maintainer-owned gate chains stay outside the region.
4654
4729
  *
4655
4730
  * `accepted` carries each generated predecessor the region can replace. The
4656
- * pack hook accepts the build chain emitted before it delegated to `build`. The
4657
- * publication hook accepts the same gate chain without
4731
+ * guides entry accepts the generated command that invoked the guides project
4732
+ * through Vitest alone. The pack hook accepts the build chain emitted before it
4733
+ * delegated to `build`. The publication hook accepts the same gate chain without
4658
4734
  * {@link RELEASE_PROOF_COMMAND}. The value being written is always writable, so
4659
4735
  * it is not repeated there. Any other value is a script the workspace author
4660
4736
  * customized, and {@link replaceManifestScripts} retains it while writing the
@@ -4673,11 +4749,11 @@ function blueprintToWritableScripts(blueprint) {
4673
4749
  const scripts = blueprintToScripts(blueprint);
4674
4750
  const writable = [];
4675
4751
  for (const [name, command] of Object.entries(scripts)) {
4676
- if (!name.startsWith("test:") || name === "test:src" || name === "test:app") continue;
4752
+ if (!(name.startsWith("test:") && name !== "test:src" && name !== "test:app")) continue;
4677
4753
  writable.push({
4678
4754
  name,
4679
4755
  command,
4680
- accepted: []
4756
+ accepted: name === "test:guides" ? ["vitest run --config vite.config.ts --no-cache --reporter=dot --project guides"] : []
4681
4757
  });
4682
4758
  }
4683
4759
  const prepack = scripts.prepack;
@@ -4779,6 +4855,7 @@ function blueprintToManifest(blueprint) {
4779
4855
  devDependencies: blueprintToDevDependencies(blueprint),
4780
4856
  ...Object.keys(peerDependencies).length > 0 ? { peerDependencies } : {},
4781
4857
  ...Object.keys(peerDependenciesMeta).length > 0 ? { peerDependenciesMeta } : {},
4858
+ devEngines: WORKSPACE_DEV_ENGINES,
4782
4859
  engines: { node: blueprint.engines }
4783
4860
  };
4784
4861
  return `${JSON.stringify(manifest, void 0, " ")}\n`;
@@ -4825,6 +4902,21 @@ function blueprintToMachinery(blueprint) {
4825
4902
  * @param blueprint - The workspace specification.
4826
4903
  * @returns Formatter-stable `tsconfig.json` text.
4827
4904
  *
4905
+ * @remarks
4906
+ * `paths` carries the workspace's own published specifiers beside the `@src` and
4907
+ * `@app` aliases, mapped to source. The published set is what
4908
+ * {@link srcToExports} publishes, read the same way here so the two never name
4909
+ * different subpaths, and the `app` axis publishes nothing so it maps nothing.
4910
+ * A package's own name resolves inside its own checkout through that `exports`
4911
+ * map, to the built `dist/` entry, so a module importing it would make the root
4912
+ * typecheck depend on a build; mapping the specifier to source is what keeps
4913
+ * `npm run check` independent of `npm run build`. The root Vite configuration
4914
+ * derives its `alias` record from every `paths` entry, so the same specifiers
4915
+ * resolve to source under Vitest, and every subpath is emitted before the bare
4916
+ * specifier: an alias record is matched in declaration order and a bare pattern
4917
+ * also matches its own subpaths, so the reverse order would resolve
4918
+ * `@orkestrel/<name>/server` through the core entry.
4919
+ *
4828
4920
  * @example
4829
4921
  * ```ts
4830
4922
  * import { blueprintToRootTsconfig, createBlueprint } from '@orkestrel/scaffold'
@@ -4836,9 +4928,21 @@ function blueprintToMachinery(blueprint) {
4836
4928
  */
4837
4929
  function blueprintToRootTsconfig(blueprint) {
4838
4930
  const aliases = [];
4839
- for (const environment of ENVIRONMENTS) if (blueprint.src.includes(environment)) aliases.push(`"@src/${environment}": ["./src/${environment}/index.ts"]`);
4840
- for (const environment of ENVIRONMENTS) if (blueprint.app.includes(environment)) aliases.push(`"@app/${environment}": ["./app/${environment}/index.ts"]`);
4841
- const paths = aliases.map((alias, index) => `\t\t\t${alias}${index === aliases.length - 1 ? "" : ","}`).join("\n");
4931
+ for (const environment of ENVIRONMENTS) if (blueprint.src.includes(environment)) aliases.push([`@src/${environment}`, `./src/${environment}/index.ts`]);
4932
+ for (const environment of ENVIRONMENTS) if (blueprint.app.includes(environment)) aliases.push([`@app/${environment}`, `./app/${environment}/index.ts`]);
4933
+ const root = srcToRoot(blueprint.src);
4934
+ if (root === void 0) for (const environment of ENVIRONMENTS) {
4935
+ if (environment === "core" || !blueprint.src.includes(environment)) continue;
4936
+ const subpath = SRC_MATRIX[environment].path.slice(1);
4937
+ aliases.push([`@orkestrel/${blueprint.name}${subpath}`, `./src/${environment}/index.ts`]);
4938
+ }
4939
+ if (blueprint.src.length > 0) aliases.push([`@orkestrel/${blueprint.name}`, `./src/${root ?? "core"}/index.ts`]);
4940
+ const paths = aliases.map(([specifier, target], index) => {
4941
+ const separator = index === aliases.length - 1 ? "" : ",";
4942
+ const line = `\t\t\t"${specifier}": ["${target}"]${separator}`;
4943
+ if (matchesPrintWidth(line)) return line;
4944
+ return `\t\t\t"${specifier}": [\n\t\t\t\t"${target}"\n\t\t\t]${separator}`;
4945
+ }).join("\n");
4842
4946
  return fillTemplate(CONFIG_TEMPLATES.root.tsconfig, { paths });
4843
4947
  }
4844
4948
  /**
@@ -5071,9 +5175,9 @@ function blueprintToConfigArtifacts(blueprint) {
5071
5175
  for (const environment of blueprint.src) for (const path of SRC_MATRIX[environment].configs) {
5072
5176
  let content = CONFIG_TEMPLATES.vites.src.core;
5073
5177
  if (path === "configs/src/tsconfig.core.json") content = CONFIG_TEMPLATES.tsconfigs.src.core;
5074
- else if (path === "configs/src/vite.browser.config.ts") content = fillTemplate(CONFIG_TEMPLATES.vites.src.browser, { replacement: nameToRewrite(blueprint.name) });
5178
+ else if (path === "configs/src/vite.browser.config.ts") content = CONFIG_TEMPLATES.vites.src.browser;
5075
5179
  else if (path === "configs/src/tsconfig.browser.json") content = CONFIG_TEMPLATES.tsconfigs.src.browser;
5076
- else if (path === "configs/src/vite.server.config.ts") content = fillTemplate(CONFIG_TEMPLATES.vites.src.server, { replacement: nameToRewrite(blueprint.name) });
5180
+ else if (path === "configs/src/vite.server.config.ts") content = CONFIG_TEMPLATES.vites.src.server;
5077
5181
  else if (path === "configs/src/tsconfig.server.json") content = CONFIG_TEMPLATES.tsconfigs.src.server;
5078
5182
  artifacts.push({
5079
5183
  path,
@@ -5516,11 +5620,11 @@ function blueprintToOrchestrationArtifacts(blueprint) {
5516
5620
  }];
5517
5621
  }
5518
5622
  /**
5519
- * Compiles the vendored host artifacts a named workspace plans.
5623
+ * Compiles the vendored host artifacts a workspace plans.
5520
5624
  *
5521
- * @param name - The target workspace's own bare package name.
5522
- * @returns One artifact per vendored path in `HOST_PATHS` order, then the
5523
- * catalog file.
5625
+ * @param blueprint - The workspace specification.
5626
+ * @returns One artifact per selected vendored path in `HOST_PATHS` order, then
5627
+ * the catalog file.
5524
5628
  *
5525
5629
  * @remarks
5526
5630
  * Every artifact is claimed by presence, which is the strongest claim a pure
@@ -5545,15 +5649,16 @@ function blueprintToOrchestrationArtifacts(blueprint) {
5545
5649
  *
5546
5650
  * @example
5547
5651
  * ```ts
5548
- * import { nameToHostArtifacts } from '@orkestrel/scaffold'
5652
+ * import { blueprintToHostArtifacts, createBlueprint } from '@orkestrel/scaffold'
5653
+ *
5654
+ * const blueprint = createBlueprint('router')
5549
5655
  *
5550
- * nameToHostArtifacts('router').some((artifact) => artifact.path === '.claude/settings.json') // true
5551
- * nameToHostArtifacts('router').some((artifact) => artifact.path === '.claude/agents/orkestrel.md') // true
5552
- * nameToHostArtifacts('router').some((artifact) => artifact.path === 'guides/router.md') // false
5656
+ * blueprintToHostArtifacts(blueprint).some((artifact) => artifact.path === 'tests/guides.test.ts') // false
5657
+ * blueprintToHostArtifacts(blueprint).some((artifact) => artifact.path === 'guides/router.md') // false
5553
5658
  * ```
5554
5659
  */
5555
- function nameToHostArtifacts(name) {
5556
- return [...selectHostPaths(HOST_PATHS, name), CATALOG_AGENT_PATH].map((path) => ({
5660
+ function blueprintToHostArtifacts(blueprint) {
5661
+ return [...selectHostPaths(HOST_PATHS, blueprint.name), CATALOG_AGENT_PATH].map((path) => ({
5557
5662
  path,
5558
5663
  group: inferGroup(path),
5559
5664
  ownership: "presence",
@@ -5596,7 +5701,8 @@ function applyOverrides(artifacts, overrides) {
5596
5701
  });
5597
5702
  }
5598
5703
  /**
5599
- * Replaces declared dependency ranges in package manifest text.
5704
+ * Replaces the runtime and development dependency ranges in package manifest text, and never a
5705
+ * peer range.
5600
5706
  *
5601
5707
  * @param manifest - The manifest text to compile.
5602
5708
  * @param pins - The runtime and development names and replacement ranges.
@@ -6482,12 +6588,18 @@ function overridesToQuestions(overrides, artifacts) {
6482
6588
  * and let the answers disagree, so a blueprint the gate will
6483
6589
  * refuse is still constructible.
6484
6590
  *
6485
- * @example
6591
+ * @example Blueprint
6486
6592
  * ```ts
6487
6593
  * import { createBlueprint } from '@orkestrel/scaffold'
6488
6594
  *
6489
- * createBlueprint('router', { src: ['core'] }).version // '0.0.1'
6490
- * createBlueprint('Router').name // 'Router' — the gate refuses it, this does not
6595
+ * const blueprint = createBlueprint('router', {
6596
+ * src: ['core', 'server'],
6597
+ * dependencies: [{ name: '@orkestrel/emitter', range: '^0.0.5' }],
6598
+ * bin: true,
6599
+ * })
6600
+ *
6601
+ * blueprint.version // '0.0.1'
6602
+ * blueprint.engines // '>=22.18.0'
6491
6603
  * ```
6492
6604
  */
6493
6605
  function createBlueprint(name, input) {
@@ -6551,11 +6663,13 @@ function createBlueprint(name, input) {
6551
6663
  *
6552
6664
  * @example
6553
6665
  * ```ts
6554
- * import { createBlueprint, Compiler } from '@orkestrel/scaffold'
6666
+ * import { Compiler, createBlueprint } from '@orkestrel/scaffold'
6555
6667
  *
6556
6668
  * const compiler = new Compiler()
6557
6669
  * const scaffolding = compiler.compile(createBlueprint('router', { src: ['core'] }))
6558
- * scaffolding.plan?.hash?.length // 16
6670
+ *
6671
+ * scaffolding.plan?.artifacts // every planned file, in group order
6672
+ * scaffolding.stages // one CompileRecord per stage that ran
6559
6673
  * compiler.destroy()
6560
6674
  * ```
6561
6675
  */
@@ -6787,7 +6901,7 @@ var Compiler = class {
6787
6901
  ...blueprintToGuideArtifacts(blueprint),
6788
6902
  ...blueprintToDocumentArtifacts(blueprint),
6789
6903
  ...blueprintToOrchestrationArtifacts(blueprint),
6790
- ...nameToHostArtifacts(blueprint.name)
6904
+ ...blueprintToHostArtifacts(blueprint)
6791
6905
  ];
6792
6906
  }
6793
6907
  #gate(blueprint, draft, artifacts) {
@@ -6818,6 +6932,6 @@ var Compiler = class {
6818
6932
  }
6819
6933
  };
6820
6934
  //#endregion
6821
- export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, ARTIFACT_TEMPLATES, BASE_DEV_DEPENDENCIES, BIN_CONFIGS, BIN_ENTRY_PATH, CANON_PATHS, CATALOG_AGENT_PATH, CATALOG_CLOSING_MARKER, CATALOG_OPENING_MARKER, CONFIG_TEMPLATES, CONFORMANCE_TEST_PATH, CONTROL_CHARACTER_PATTERN, Compiler, DECLARATION_DEV_DEPENDENCIES, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, DISTRIBUTION_TEST_PATH, ENGINES_PATTERN, ENVIRONMENTS, EXECUTABLE_PATHS, EXTRA_RANGE_PATTERN, FLOOR_RANGE_PATTERN, FOREIGN_NAME_PATTERN, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HEX_PATTERN, HOST_INVENTORY_PATH, HOST_PATHS, INTEGRATION_TEST_PATH, INVALID_PATH_CHARACTER_PATTERN, MANIFEST_PATH, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_AUDIT_FINDINGS, MAX_COLLECTION_ITEMS, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_REGISTRY_BYTES, MAX_SCRIPT_LENGTH, MAX_TOTAL_ARTIFACT_BYTES, MAX_TOTAL_REGISTRY_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORCHESTRATION_PATH_NAMES, ORCHESTRATION_PATH_PREFIXES, ORKESTREL_RANGE_PATTERN, PRINT_WIDTH, RELEASE_PROOF_COMMAND, SERVICE_SCRIPT_PATH, SERVICE_SETUP_PATH, SERVICE_TEST_INCLUDE, SHOWCASE_CONFIG_PATH, SHOWCASE_DEV_DEPENDENCIES, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, ScaffoldError, TAB_WIDTH, VERSION_PATTERN, WORKSPACE_OWNED_PATHS, applyOverrides, artifactToFinding, artifactToHex, artifactsToQuestions, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToDocumentArtifacts, blueprintToGuideArtifacts, blueprintToMachinery, blueprintToManifest, blueprintToOrchestrationArtifacts, blueprintToQuestions, blueprintToRootTsconfig, blueprintToRootVite, blueprintToScripts, blueprintToSourceArtifacts, blueprintToTestArtifacts, blueprintToWritableScripts, bytesToHex, catalogToLayers, cloneValue, compareVersions, computeBytes, computeHash, contentToHex, createBlueprint, dependenciesToQuestions, extractRangeMajor, extractVersion, inferDrift, inferGroup, isArtifact, isAudit, isBlueprint, isCanonPath, isCatalogEntry, isCollection, isCompilerHooks, isCompilerOptions, isContent, isDeferredPath, isDependency, isDependencyName, isEnvironment, isFinding, isFloorPath, isGroup, isGroups, isHex, isManifestScript, isMirror, isOverride, isPath, isPlan, isQuestion, isRetainedPath, isScaffoldError, isSnapshot, manifestToDependencies, manifestToName, matchesDriftReachability, matchesEngines, matchesOrchestrationPath, matchesPrintWidth, matchesRange, nameToGuide, nameToHostArtifacts, nameToRewrite, overridesToQuestions, parseBlueprint, parseCompilerOptions, parseGroups, parseSnapshot, pathToCondition, planToFindings, planToHash, planToSummary, replaceManifestRanges, replaceManifestScripts, replacePlanRanges, selectGroups, selectHostPaths, serializeTypeScriptString, srcToEntry, srcToExports, srcToRoot };
6935
+ export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, ARTIFACT_TEMPLATES, BASE_DEV_DEPENDENCIES, BIN_CONFIGS, BIN_ENTRY_PATH, CANON_PATHS, CATALOG_AGENT_PATH, CATALOG_CLOSING_MARKER, CATALOG_OPENING_MARKER, CONFIG_TEMPLATES, CONFORMANCE_TEST_PATH, CONTROL_CHARACTER_PATTERN, Compiler, DECLARATION_DEV_DEPENDENCIES, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, DISTRIBUTION_TEST_PATH, ENGINES_PATTERN, ENVIRONMENTS, EXECUTABLE_PATHS, EXTRA_RANGE_PATTERN, FLOOR_RANGE_PATTERN, FOREIGN_NAME_PATTERN, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HEX_PATTERN, HOST_INVENTORY_PATH, HOST_PATHS, INTEGRATION_TEST_PATH, INVALID_PATH_CHARACTER_PATTERN, MANIFEST_PATH, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_AUDIT_FINDINGS, MAX_COLLECTION_ITEMS, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_REGISTRY_BYTES, MAX_SCRIPT_LENGTH, MAX_TOTAL_ARTIFACT_BYTES, MAX_TOTAL_REGISTRY_BYTES, MINIMUM_NODE_VERSION, MINIMUM_NPM_VERSION, NAME_PATTERN, ORCHESTRATION_PATH_NAMES, ORCHESTRATION_PATH_PREFIXES, ORKESTREL_RANGE_PATTERN, PRINT_WIDTH, RELEASE_PROOF_COMMAND, SERVICE_SCRIPT_PATH, SERVICE_SETUP_PATH, SERVICE_TEST_INCLUDE, SHOWCASE_CONFIG_PATH, SHOWCASE_DEV_DEPENDENCIES, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, ScaffoldError, TAB_WIDTH, VERSION_PATTERN, WORKSPACE_DEV_ENGINES, WORKSPACE_OWNED_PATHS, applyOverrides, artifactToFinding, artifactToHex, artifactsToQuestions, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToDocumentArtifacts, blueprintToGuideArtifacts, blueprintToHostArtifacts, blueprintToMachinery, blueprintToManifest, blueprintToOrchestrationArtifacts, blueprintToQuestions, blueprintToRootTsconfig, blueprintToRootVite, blueprintToScripts, blueprintToSourceArtifacts, blueprintToTestArtifacts, blueprintToWritableScripts, bytesToHex, catalogToLayers, cloneValue, compareVersions, computeBytes, computeHash, contentToHex, createBlueprint, dependenciesToQuestions, extractRangeMajor, extractVersion, inferDrift, inferGroup, isArtifact, isAudit, isBlueprint, isCanonPath, isCatalogEntry, isCollection, isCompilerHooks, isCompilerOptions, isContent, isDeferredPath, isDependency, isDependencyName, isEnvironment, isFinding, isFloorPath, isGroup, isGroups, isHex, isManifestScript, isMirror, isOverride, isPath, isPlan, isQuestion, isRetainedPath, isScaffoldError, isSnapshot, manifestToDependencies, manifestToName, matchesDriftReachability, matchesEngines, matchesOrchestrationPath, matchesPrintWidth, matchesRange, nameToGuide, overridesToQuestions, parseBlueprint, parseCompilerOptions, parseGroups, parseSnapshot, pathToCondition, planToFindings, planToHash, planToSummary, replaceManifestRanges, replaceManifestScripts, replacePlanRanges, selectGroups, selectHostPaths, serializeTypeScriptString, srcToEntry, srcToExports, srcToRoot };
6822
6936
 
6823
6937
  //# sourceMappingURL=index.js.map