@orkestrel/scaffold 0.0.80 → 0.0.82

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 (36) hide show
  1. package/dist/bin/main.js +167 -13
  2. package/dist/bin/main.js.map +1 -1
  3. package/dist/host/AGENTS.md +5 -3
  4. package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +2 -2
  5. package/dist/host/agents/skills/orkestrel-journey/SKILL.md +41 -38
  6. package/dist/host/agents/skills/orkestrel-journey/references/captures.md +3 -3
  7. package/dist/host/agents/skills/orkestrel-journey/references/decide.md +3 -3
  8. package/dist/host/agents/skills/orkestrel-journey/references/layer.md +5 -5
  9. package/dist/host/agents/skills/orkestrel-journey/references/statechart.md +3 -3
  10. package/dist/host/agents/skills/orkestrel-journey/references/styles.md +9 -9
  11. package/dist/host/claude/agents/orkestrel.md +52 -52
  12. package/dist/host/claude/rules/application.md +20 -6
  13. package/dist/host/claude/rules/architecture.md +2 -2
  14. package/dist/host/claude/rules/browser.md +9 -0
  15. package/dist/host/claude/rules/documentation.md +2 -1
  16. package/dist/host/claude/rules/styles.md +35 -12
  17. package/dist/host/claude/rules/tests.md +15 -10
  18. package/dist/host/claude/rules/workspace.md +128 -98
  19. package/dist/host/claude/skills/orkestrel-journey/SKILL.md +1 -1
  20. package/dist/host/configs/helpers.ts +157 -9
  21. package/dist/host/configs/policy.ts +64 -61
  22. package/dist/host/dotfiles/oxlintrc.json +132 -16
  23. package/dist/host/dotfiles/prettierignore +1 -1
  24. package/dist/host/guides/README.md +9 -5
  25. package/dist/host/guides/scaffold.md +475 -115
  26. package/dist/host/manifest.json +27 -27
  27. package/dist/host/tests/config.test.ts +996 -39
  28. package/dist/host/tests/policy.test.ts +11 -0
  29. package/dist/host/tests/setupPolicy.ts +396 -22
  30. package/dist/src/core/index.cjs +1263 -161
  31. package/dist/src/core/index.cjs.map +1 -1
  32. package/dist/src/core/index.d.cts +297 -35
  33. package/dist/src/core/index.d.ts +297 -35
  34. package/dist/src/core/index.js +1243 -162
  35. package/dist/src/core/index.js.map +1 -1
  36. package/package.json +3 -3
@@ -3,7 +3,7 @@ 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.80",
6
+ version: "0.0.82",
7
7
  description: "Scaffold workspaces with commands: new, audit, repair, catalog, and overwrite.",
8
8
  keywords: [
9
9
  "audit",
@@ -102,9 +102,9 @@ var package_default = {
102
102
  },
103
103
  devDependencies: {
104
104
  "@microsoft/api-extractor": "^7.59.3",
105
- "@orkestrel/guide": "^0.0.20",
105
+ "@orkestrel/guide": "^0.0.21",
106
106
  "@orkestrel/html": "^0.0.11",
107
- "@orkestrel/probe": "^0.0.18",
107
+ "@orkestrel/probe": "^0.0.19",
108
108
  "@orkestrel/test": "^0.0.24",
109
109
  "@types/node": "^26.6.3",
110
110
  "@vitest/browser-playwright": "^4.1.11",
@@ -133,6 +133,44 @@ var ENVIRONMENTS = Object.freeze([
133
133
  "browser",
134
134
  "server"
135
135
  ]);
136
+ /** Lists the surfaces an extension may extend, frozen. */
137
+ var SURFACES = Object.freeze(["browser", "styles"]);
138
+ /** Lists the axes a browser extension may occupy, frozen. */
139
+ var AXES = Object.freeze(["src", "app"]);
140
+ /** Lists the supported browser frameworks, frozen. */
141
+ var FRAMEWORKS = Object.freeze(["vue"]);
142
+ /** Describes the tooling and package boundaries of each browser framework, frozen. */
143
+ var FRAMEWORK_MATRIX = Object.freeze({ vue: Object.freeze({
144
+ plugin: "@vitejs/plugin-vue",
145
+ checker: "vue-tsc",
146
+ suffixes: Object.freeze(["vue"]),
147
+ refused: Object.freeze(["vue", "@vue/"]),
148
+ dependencies: Object.freeze({
149
+ "@vitejs/plugin-vue": "^6.0.8",
150
+ vue: "^3.5.40",
151
+ "vue-tsc": "^3.3.7"
152
+ })
153
+ }) });
154
+ /** Names the base stylesheet marker. */
155
+ var STYLES_ENTRY_PATH = "src/styles/index.scss";
156
+ /** Names the themes build entry marker. */
157
+ var THEMES_ENTRY_PATH = "src/styles/themes/sheet.ts";
158
+ /** Names the themes stylesheet marker. */
159
+ var THEMES_BARREL_PATH = "src/styles/themes/index.scss";
160
+ /** Names the build entry beside each stylesheet marker. */
161
+ var SHEET_ENTRY_NAME = "sheet.ts";
162
+ /** Names the physical showcase output directory. */
163
+ var SHOWCASE_PAGES_PATH = "showcase";
164
+ /** Lists the development dependencies the styles surface adds, frozen. */
165
+ var STYLES_DEV_DEPENDENCIES = Object.freeze({ sass: "^1.105.1" });
166
+ /** Lists the names a styles extension cannot occupy, frozen. */
167
+ var RESERVED_SHEET_NAMES = Object.freeze([
168
+ ...ENVIRONMENTS,
169
+ "bin",
170
+ "styles",
171
+ "themes",
172
+ ...FRAMEWORKS
173
+ ]);
136
174
  /**
137
175
  * Lists the `Group` values in plan order, frozen.
138
176
  *
@@ -625,13 +663,10 @@ var SOURCE_BROWSER_DEV_DEPENDENCIES = Object.freeze({
625
663
  });
626
664
  /** Names the development dependency every private `app` environment adds. */
627
665
  var APP_DEV_DEPENDENCIES = Object.freeze({ "@orkestrel/contract": package_default.dependencies["@orkestrel/contract"] });
628
- /** Lists the development dependencies a private Vue browser application adds. */
666
+ /** Lists the development dependencies a private browser application adds. */
629
667
  var APP_BROWSER_DEV_DEPENDENCIES = Object.freeze({
630
668
  ...SOURCE_BROWSER_DEV_DEPENDENCIES,
631
- "@orkestrel/html": package_default.devDependencies["@orkestrel/html"],
632
- "@vitejs/plugin-vue": "^6.0.8",
633
- vue: "^3.5.40",
634
- "vue-tsc": "^3.3.7"
669
+ "@orkestrel/html": package_default.devDependencies["@orkestrel/html"]
635
670
  });
636
671
  /**
637
672
  * Names the development dependency used only by the optional single-file showcase build.
@@ -695,9 +730,7 @@ var CONFIG_TEMPLATES = Object.freeze({
695
730
  "forceConsistentCasingInFileNames": true,
696
731
  "skipLibCheck": true,
697
732
  "noEmit": true,
698
- "paths": {
699
733
  {{paths}}
700
- }
701
734
  },
702
735
  "exclude": ["node_modules", "dist", "tmp"]
703
736
  }
@@ -814,6 +847,27 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
814
847
  `
815
848
  }),
816
849
  factories: Object.freeze({
850
+ sheet: `export function sheetProject(name: string, override?: UserConfig): UserConfig {
851
+ const project: UserConfig = {
852
+ resolve,
853
+ optimizeDeps,
854
+ publicDir: false,
855
+ test: {
856
+ name: { label: name, color: 'magenta' },
857
+ root: resolveWorkspacePath('.'),
858
+ isolate: false,
859
+ setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts', './tests/setupStyles.ts'],
860
+ browser: {
861
+ enabled: true,
862
+ provider: playwright(browserOptions),
863
+ instances: [{ browser: 'chromium', headless: true }],
864
+ },
865
+ fileParallelism: false,
866
+ },
867
+ }
868
+ return mergeOverride(project, override)
869
+ }
870
+ `,
817
871
  src: Object.freeze({
818
872
  core: `export function srcCore(override?: UserConfig): UserConfig {
819
873
  const project: UserConfig = {
@@ -836,9 +890,51 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
836
890
  return mergeOverride(project, override)
837
891
  }
838
892
  `,
839
- browser: `export function srcBrowser(override?: UserConfig): UserConfig {
893
+ vue: `function resolveVueFilename(): string {
894
+ return 'index.js'
895
+ }
896
+
897
+ export function srcVue(override?: UserConfig): UserConfig {
898
+ const project: UserConfig = {
899
+ resolve,
900
+ optimizeDeps: { include: [...optimizeDeps.include, 'vue'] },
901
+ publicDir: false,
902
+ plugins: [outputBoundary('dist/src/vue'), environmentBoundary('src/vue'), vue()],
903
+ build: {
904
+ emptyOutDir: true,
905
+ sourcemap: true,
906
+ minify: false,
907
+ lib: {
908
+ entry: resolveWorkspacePath('src/vue/index.ts'),
909
+ formats: ['es'],
910
+ fileName: resolveVueFilename,
911
+ },
912
+ outDir: 'dist/src/vue',
913
+ rolldownOptions: { onLog: enforceBuildLog },
914
+ },
915
+ test: {
916
+ name: { label: 'src:vue', color: 'green' },
917
+ include: ['tests/src/vue/**/*.test.ts'],
918
+ setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
919
+ browser: {
920
+ enabled: true,
921
+ provider: playwright(browserOptions),
922
+ instances: [{ browser: 'chromium', headless: true }],
923
+ },
924
+ fileParallelism: false,
925
+ },
926
+ }
927
+ return mergeOverride(project, override)
928
+ }
929
+ `,
930
+ browser: `function resolveBrowserFilename(): string {
931
+ return 'index.js'
932
+ }
933
+
934
+ export function srcBrowser(override?: UserConfig): UserConfig {
840
935
  const project: UserConfig = {
841
936
  resolve,
937
+ optimizeDeps,
842
938
  publicDir: false,
843
939
  plugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],
844
940
  build: {
@@ -848,7 +944,7 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
848
944
  lib: {
849
945
  entry: resolveWorkspacePath('src/browser/index.ts'),
850
946
  formats: ['es'],
851
- fileName: () => 'index.js',
947
+ fileName: resolveBrowserFilename,
852
948
  },
853
949
  outDir: 'dist/src/browser',
854
950
  rolldownOptions: {
@@ -873,7 +969,11 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
873
969
  return mergeOverride(project, override)
874
970
  }
875
971
  `,
876
- server: `export function srcServer(override?: UserConfig): UserConfig {
972
+ server: `function resolveServerFilename(format: string): string {
973
+ return format === 'es' ? 'index.js' : 'index.cjs'
974
+ }
975
+
976
+ export function srcServer(override?: UserConfig): UserConfig {
877
977
  const project: UserConfig = {
878
978
  resolve,
879
979
  publicDir: false,
@@ -885,7 +985,7 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
885
985
  lib: {
886
986
  entry: resolveWorkspacePath('src/server/index.ts'),
887
987
  formats: ['es', 'cjs'],
888
- fileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),
988
+ fileName: resolveServerFilename,
889
989
  },
890
990
  outDir: 'dist/src/server',
891
991
  target: 'node22',
@@ -907,7 +1007,15 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
907
1007
  return mergeOverride(project, override)
908
1008
  }
909
1009
  `,
910
- bin: `export function srcBin(override?: UserConfig): UserConfig {
1010
+ bin: `function resolveBinFilename(): string {
1011
+ return 'main.js'
1012
+ }
1013
+
1014
+ function resolveBinExternal(id: string): boolean {
1015
+ return id.startsWith('@src/') || resolveExternal(id, { peers, refused: [], siblings: [] })
1016
+ }
1017
+
1018
+ export function srcBin(override?: UserConfig): UserConfig {
911
1019
  const project: UserConfig = {
912
1020
  resolve,
913
1021
  publicDir: false,
@@ -919,17 +1027,13 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
919
1027
  lib: {
920
1028
  entry: resolveWorkspacePath('${BIN_ENTRY_PATH}'),
921
1029
  formats: ['es'],
922
- fileName: () => 'main.js',
1030
+ fileName: resolveBinFilename,
923
1031
  },
924
1032
  outDir: 'dist/bin',
925
1033
  target: 'node22',
926
1034
  rolldownOptions: {
927
1035
  onLog: enforceBuildLog,
928
- external: (id: string) =>
929
- id.startsWith('node:') ||
930
- id.startsWith('@orkestrel/') ||
931
- id.startsWith('@src/') ||
932
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),
1036
+ external: resolveBinExternal,
933
1037
  },
934
1038
  },
935
1039
  test: {
@@ -969,7 +1073,8 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
969
1073
  const output = 'dist/app/browser'
970
1074
  const project: UserConfig = {
971
1075
  resolve,
972
- plugins: [outputBoundary(output), environmentBoundary('app/browser'), vue()],
1076
+ optimizeDeps,
1077
+ plugins: [outputBoundary(output), environmentBoundary('app/browser')],
973
1078
  root: resolveWorkspacePath('app/browser'),
974
1079
  publicDir: false,
975
1080
  build: {
@@ -998,20 +1103,47 @@ function isNamedPlugin(plugin: PluginOption): plugin is { name: string } {
998
1103
  return mergeOverride(project, override)
999
1104
  }
1000
1105
  {{showcaseFactory}}{{journeyFactory}}`,
1106
+ vue: `export function appVue(override?: UserConfig): UserConfig {
1107
+ const output = 'dist/app/vue'
1108
+ const browser = appBrowser()
1109
+ const project: UserConfig = {
1110
+ ...browser,
1111
+ optimizeDeps: { include: [...optimizeDeps.include, 'vue'] },
1112
+ plugins: [outputBoundary(output), environmentBoundary('app/vue'), vue()],
1113
+ root: resolveWorkspacePath('app/vue'),
1114
+ build: {
1115
+ ...browser.build,
1116
+ outDir: resolveWorkspacePath(output),
1117
+ rolldownOptions: {
1118
+ ...browser.build?.rolldownOptions,
1119
+ input: resolveWorkspacePath('app/vue/index.html'),
1120
+ },
1121
+ },
1122
+ test: {
1123
+ ...browser.test,
1124
+ name: { label: 'app:vue', color: 'magenta' },
1125
+ include: ['tests/app/vue/**/*.test.ts'],
1126
+ {{journeyExclude}} },
1127
+ }
1128
+ return mergeOverride(project, override)
1129
+ }
1130
+ `,
1001
1131
  journey: `
1002
1132
  // Replace the journey fields directly: merging would concatenate the ordinary include
1003
1133
  // and retain the exclusion of the journey suite.
1004
1134
  export function appJourney(
1005
1135
  variant: JourneyVariant,
1006
1136
  variants: readonly JourneyVariant[],
1137
+ mode?: string,
1007
1138
  ): UserConfig {
1008
- const browser = appBrowser()
1139
+ const application = resolveApplication(mode, applications)
1140
+ const browser = applications[application]()
1009
1141
  return {
1010
1142
  ...browser,
1011
1143
  test: {
1012
1144
  ...browser.test,
1013
1145
  name: { label: \`journey:\${variant.name}\`, color: 'green' },
1014
- include: ['tests/app/browser/integration.test.ts'],
1146
+ include: [\`tests/app/\${application}/integration.test.ts\`],
1015
1147
  exclude: [],
1016
1148
  provide: { variant: variant.name, variants, capture },
1017
1149
  browser: {
@@ -1024,8 +1156,39 @@ export function appJourney(
1024
1156
  }
1025
1157
  `,
1026
1158
  showcase: `
1027
- export function appShowcase(override?: UserConfig): UserConfig {
1028
- const output = 'dist/showcase'
1159
+ const showcaseStamp: PluginOption = {
1160
+ name: 'orkestrel-showcase-html',
1161
+ enforce: 'post',
1162
+ generateBundle(_, bundle) {
1163
+ for (const file of Object.values(bundle)) {
1164
+ if (
1165
+ file.type === 'asset' &&
1166
+ typeof file.source === 'string' &&
1167
+ file.fileName.endsWith('.html')
1168
+ ) {
1169
+ file.source = stampPage(file.source)
1170
+ }
1171
+ }
1172
+ },
1173
+ }
1174
+
1175
+ function createShowcaseNaming(application: string): PluginOption {
1176
+ return {
1177
+ name: 'orkestrel-showcase-name',
1178
+ enforce: 'post',
1179
+ writeBundle(options) {
1180
+ if (options.dir === undefined) throw new Error('The showcase output is absent.')
1181
+ renameSync(
1182
+ resolvePath(options.dir, 'index.html'),
1183
+ resolvePath(options.dir, application + '.html'),
1184
+ )
1185
+ },
1186
+ }
1187
+ }
1188
+
1189
+ export function appShowcase(mode: string, override?: UserConfig): UserConfig {
1190
+ const application = resolveApplication(mode, applications)
1191
+ const output = 'showcase'
1029
1192
  const showcase: UserConfig = {
1030
1193
  plugins: [
1031
1194
  outputBoundary(output),
@@ -1033,19 +1196,8 @@ export function appShowcase(override?: UserConfig): UserConfig {
1033
1196
  removeViteModuleLoader: true,
1034
1197
  useRecommendedBuildConfig: true,
1035
1198
  }),
1036
- {
1037
- name: 'orkestrel-showcase-html',
1038
- transformIndexHtml: {
1039
- order: 'post',
1040
- handler(html) {
1041
- const stamp = new Date().toISOString()
1042
- return html.replace(
1043
- '</head>',
1044
- '\t\t<meta name="build-id" content="' + stamp + '" />\\n\t</head>',
1045
- )
1046
- },
1047
- },
1048
- },
1199
+ showcaseStamp,
1200
+ createShowcaseNaming(application),
1049
1201
  ],
1050
1202
  build: {
1051
1203
  // The \`appBrowser\` factory sets \`assetsInlineLimit\` to 0, so every asset becomes
@@ -1054,6 +1206,7 @@ export function appShowcase(override?: UserConfig): UserConfig {
1054
1206
  // true, so this line takes effect only in a workspace that turns that option off.
1055
1207
  assetsInlineLimit: 4096,
1056
1208
  cssMinify: 'lightningcss',
1209
+ emptyOutDir: false,
1057
1210
  minify: 'oxc',
1058
1211
  modulePreload: false,
1059
1212
  outDir: resolveWorkspacePath(output),
@@ -1062,10 +1215,18 @@ export function appShowcase(override?: UserConfig): UserConfig {
1062
1215
  target: 'esnext',
1063
1216
  },
1064
1217
  }
1065
- return appBrowser(mergeOverride(showcase, override))
1218
+ return applications[application](mergeOverride(showcase, override))
1066
1219
  }
1067
1220
  `,
1068
- server: `export function appServer(override?: UserConfig): UserConfig {
1221
+ server: `function resolveAppFilename(): string {
1222
+ return 'main.cjs'
1223
+ }
1224
+
1225
+ function resolveAppExternal(id: string): boolean {
1226
+ return id.startsWith('node:')
1227
+ }
1228
+
1229
+ export function appServer(override?: UserConfig): UserConfig {
1069
1230
  const project: UserConfig = {
1070
1231
  resolve,
1071
1232
  publicDir: false,
@@ -1075,13 +1236,13 @@ export function appShowcase(override?: UserConfig): UserConfig {
1075
1236
  lib: {
1076
1237
  entry: resolveWorkspacePath('app/server/main.ts'),
1077
1238
  formats: ['cjs'],
1078
- fileName: () => 'main.cjs',
1239
+ fileName: resolveAppFilename,
1079
1240
  },
1080
1241
  outDir: resolveWorkspacePath('dist/app/server'),
1081
1242
  target: 'node22',
1082
1243
  rolldownOptions: {
1083
1244
  onLog: enforceBuildLog,
1084
- external: (id: string) => id.startsWith('node:'),
1245
+ external: resolveAppExternal,
1085
1246
  },
1086
1247
  },
1087
1248
  test: {
@@ -1134,8 +1295,10 @@ export function appShowcase(override?: UserConfig): UserConfig {
1134
1295
  test: {
1135
1296
  name: { label: 'setup', color: 'white' },
1136
1297
  include: ['tests/setup*.test.ts'],
1137
- exclude: ['tests/setupBrowser.test.ts'],
1298
+ exclude: ['tests/setupBrowser.test.ts', 'tests/setupStyles.test.ts'],
1138
1299
  setupFiles: ['./tests/setup.ts'],
1300
+ pool: 'threads',
1301
+ isolate: false,
1139
1302
  environment: 'node',
1140
1303
  browser: { enabled: false },
1141
1304
  },
@@ -1146,9 +1309,10 @@ export function appShowcase(override?: UserConfig): UserConfig {
1146
1309
  browser: `export function setupBrowser(override?: UserConfig): UserConfig {
1147
1310
  const project: UserConfig = {
1148
1311
  resolve,
1312
+ {{optimization}},
1149
1313
  {{plugins}} test: {
1150
1314
  name: { label: 'setup:browser', color: 'blue' },
1151
- include: ['tests/setupBrowser.test.ts'],
1315
+ include: ['tests/setupBrowser.test.ts', 'tests/setupStyles.test.ts'],
1152
1316
  setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
1153
1317
  {{global}} browser: {
1154
1318
  enabled: true,
@@ -1202,7 +1366,9 @@ export function conformance(override?: UserConfig): UserConfig {
1202
1366
  test: {
1203
1367
  name: { label: 'conformance', color: 'magenta' },
1204
1368
  include: ['${CONFORMANCE_TEST_PATH}'],
1205
- setupFiles: ['./tests/setup.ts'],
1369
+ setupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],
1370
+ pool: 'threads',
1371
+ isolate: false,
1206
1372
  environment: 'node',
1207
1373
  browser: { enabled: false },
1208
1374
  },
@@ -1268,7 +1434,17 @@ export function probe(override?: UserConfig): UserConfig {
1268
1434
  return mergeOverride(project, override)
1269
1435
  }
1270
1436
  `,
1271
- integration: `export function integration(override?: UserConfig): UserConfig {
1437
+ integration: Object.freeze({
1438
+ sheet: `export function integration(override?: UserConfig): UserConfig {
1439
+ const project = sheetProject('integration', {
1440
+ test: {
1441
+ include: ['tests/integration.test.ts'],
1442
+ {{global}} },
1443
+ })
1444
+ return mergeOverride(project, override)
1445
+ }
1446
+ `,
1447
+ module: `export function integration(override?: UserConfig): UserConfig {
1272
1448
  const project: UserConfig = {
1273
1449
  resolve,
1274
1450
  test: {
@@ -1281,8 +1457,51 @@ export function probe(override?: UserConfig): UserConfig {
1281
1457
  return mergeOverride(project, override)
1282
1458
  }
1283
1459
  `
1460
+ })
1284
1461
  }),
1285
1462
  tsconfigs: Object.freeze({
1463
+ vue: Object.freeze({
1464
+ src: `{
1465
+ "extends": "../../tsconfig.json",
1466
+ "compilerOptions": {
1467
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
1468
+ "types": ["vite/client"],
1469
+ "noEmit": false,
1470
+ "declaration": true,
1471
+ "emitDeclarationOnly": true,
1472
+ "rootDir": "../../src",
1473
+ "outDir": "../../dist/src"
1474
+ },
1475
+ "include": [
1476
+ "../../src/vue/**/*.cts",
1477
+ "../../src/vue/**/*.mts",
1478
+ "../../src/vue/**/*.ts",
1479
+ "../../src/vue/**/*.tsx"
1480
+ ]
1481
+ }
1482
+ `,
1483
+ app: `{
1484
+ "extends": "../../tsconfig.json",
1485
+ "compilerOptions": {
1486
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
1487
+ "types": ["vite/client", "vue"]
1488
+ },
1489
+ "include": [
1490
+ {{include}}
1491
+ ]
1492
+ }
1493
+ `
1494
+ }),
1495
+ sheet: `{
1496
+ "extends": "../../tsconfig.json",
1497
+ "compilerOptions": {
1498
+ "lib": ["ESNext"],
1499
+ "types": ["vite/client"],
1500
+ "noEmit": true
1501
+ },
1502
+ "include": ["../../src/{{name}}/**/*.ts"]
1503
+ }
1504
+ `,
1286
1505
  src: Object.freeze({
1287
1506
  core: `{
1288
1507
  "extends": "../../tsconfig.json",
@@ -1366,7 +1585,7 @@ export function probe(override?: UserConfig): UserConfig {
1366
1585
  "extends": "../../tsconfig.json",
1367
1586
  "compilerOptions": {
1368
1587
  "lib": ["ESNext", "DOM", "DOM.Iterable"],
1369
- "types": ["vite/client", "vue"]
1588
+ "types": ["vite/client"]
1370
1589
  },
1371
1590
  "include": [
1372
1591
  {{include}}
@@ -1416,9 +1635,38 @@ export function probe(override?: UserConfig): UserConfig {
1416
1635
  `
1417
1636
  }),
1418
1637
  vites: Object.freeze({
1638
+ sheet: `import { defineConfig } from 'vitest/config'
1639
+ import { outputBoundary } from '../helpers.js'
1640
+ import { resolveWorkspacePath, sheetProject } from '../../vite.config.ts'
1641
+
1642
+ export default defineConfig((invocation) => {
1643
+ const project = sheetProject('src:{{label}}', {
1644
+ plugins: [outputBoundary('dist/src/{{name}}')],
1645
+ build: {
1646
+ outDir: 'dist/src/{{name}}',
1647
+ emptyOutDir: true,
1648
+ // Preserve the authored layer-order statement in the published sheet.
1649
+ cssMinify: false,
1650
+ lib: {
1651
+ entry: resolveWorkspacePath('src/{{name}}/sheet.ts'),
1652
+ formats: ['es'],
1653
+ fileName: 'index',
1654
+ cssFileName: 'index',
1655
+ },
1656
+ },
1657
+ test: { include: ['tests/src/{{name}}/**/*.test.ts'] },
1658
+ })
1659
+ return { ...project, mode: invocation.mode }
1660
+ })
1661
+ `,
1419
1662
  src: Object.freeze({
1420
1663
  core: `import { defineConfig } from 'vite'
1421
- import { declarationRollup, environmentBoundary, outputBoundary } from '../helpers.js'
1664
+ import {
1665
+ declarationRollup,
1666
+ environmentBoundary,
1667
+ outputBoundary,
1668
+ resolveExternal,
1669
+ } from '../helpers.js'
1422
1670
  import { peers, srcCore, resolveWorkspacePath } from '../../vite.config.ts'
1423
1671
 
1424
1672
  export default defineConfig(
@@ -1439,11 +1687,43 @@ export default defineConfig(
1439
1687
  fileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),
1440
1688
  },
1441
1689
  outDir: 'dist/src/core',
1690
+ rolldownOptions: {
1691
+ external: (id: string) => resolveExternal(id, { peers, refused: [], siblings: [] }),
1692
+ },
1693
+ },
1694
+ }),
1695
+ )
1696
+ `,
1697
+ vue: `import { defineConfig } from 'vite'
1698
+ import {
1699
+ declarationRollup,
1700
+ resolveExternal,
1701
+ rewriteBrowserSpecifier,
1702
+ rewriteCoreSpecifier,
1703
+ } from '../helpers.js'
1704
+ import { peers, srcVue, resolveWorkspacePath } from '../../vite.config.ts'
1705
+
1706
+ const siblings = {
1707
+ {{siblings}}
1708
+ }
1709
+
1710
+ export default defineConfig(
1711
+ srcVue({
1712
+ plugins: [
1713
+ declarationRollup({
1714
+ project: resolveWorkspacePath('configs/src/tsconfig.vue.json'),
1715
+ rewrite: (content) => rewriteBrowserSpecifier(rewriteCoreSpecifier(content)),
1716
+ }),
1717
+ ],
1718
+ build: {
1442
1719
  rolldownOptions: {
1443
1720
  external: (id: string) =>
1444
- id.startsWith('node:') ||
1445
- id.startsWith('@orkestrel/') ||
1446
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),
1721
+ resolveExternal(id, {
1722
+ peers,
1723
+ refused: {{refused}},
1724
+ siblings: Object.keys(siblings),
1725
+ }),
1726
+ output: { paths: siblings },
1447
1727
  },
1448
1728
  },
1449
1729
  }),
@@ -1485,7 +1765,8 @@ export default defineConfig(
1485
1765
  `
1486
1766
  }),
1487
1767
  bin: `import { defineConfig } from 'vite'
1488
- import { srcBin } from '../../vite.config.ts'
1768
+ import { resolveExternal } from '../helpers.js'
1769
+ import { peers, srcBin } from '../../vite.config.ts'
1489
1770
 
1490
1771
  // The \`scaffold\` executable build — a single ESM lib file, no declarations (an
1491
1772
  // executable ships no types), with the \`#!/usr/bin/env node\` shebang re-emitted through
@@ -1496,6 +1777,8 @@ export default defineConfig(
1496
1777
  srcBin({
1497
1778
  build: {
1498
1779
  rolldownOptions: {
1780
+ external: (id: string) =>
1781
+ id.startsWith('@src/') || resolveExternal(id, { peers, refused: [], siblings: [] }),
1499
1782
  output: {
1500
1783
  banner: '#!/usr/bin/env node',
1501
1784
  {{paths}}
@@ -1506,6 +1789,11 @@ export default defineConfig(
1506
1789
  )
1507
1790
  `,
1508
1791
  app: Object.freeze({
1792
+ vue: `import { defineConfig } from 'vite'
1793
+ import { appVue } from '../../vite.config.ts'
1794
+
1795
+ export default defineConfig(appVue())
1796
+ `,
1509
1797
  browser: `import { defineConfig } from 'vite'
1510
1798
  import { appBrowser } from '../../vite.config.ts'
1511
1799
 
@@ -1519,7 +1807,7 @@ export default defineConfig(appServer())
1519
1807
  showcase: `import { defineConfig } from 'vite'
1520
1808
  import { appShowcase } from '../../vite.config.ts'
1521
1809
 
1522
- export default defineConfig(appShowcase())
1810
+ export default defineConfig(({ mode }) => appShowcase(mode))
1523
1811
  `,
1524
1812
  journey: `import type { JourneyVariant } from '@orkestrel/test'
1525
1813
  import { defineConfig } from 'vitest/config'
@@ -1531,11 +1819,11 @@ const VARIANTS: readonly JourneyVariant[] = Object.freeze([
1531
1819
  { name: 'compact', width: 390, height: 844 },
1532
1820
  ])
1533
1821
 
1534
- export default defineConfig({
1822
+ export default defineConfig(({ mode }) => ({
1535
1823
  test: {
1536
- projects: VARIANTS.map((variant) => () => appJourney(variant, VARIANTS)),
1824
+ projects: VARIANTS.map((variant) => () => appJourney(variant, VARIANTS, mode)),
1537
1825
  },
1538
- })
1826
+ }))
1539
1827
  `
1540
1828
  })
1541
1829
  }),
@@ -1878,7 +2166,38 @@ export function resolveBrowser(
1878
2166
  */
1879
2167
  var ARTIFACT_TEMPLATES = Object.freeze({
1880
2168
  source: Object.freeze({
2169
+ sheet: Object.freeze({
2170
+ "index.scss": "@use 'tokens';\n@use 'elements';\n@use 'components';\n@use 'utilities';\n",
2171
+ "_tokens.scss": "@layer theme, reset, base, elements, components, utilities;\n",
2172
+ "_mixins.scss": "",
2173
+ "elements/_index.scss": "",
2174
+ "components/_index.scss": "",
2175
+ "utilities/_index.scss": "",
2176
+ "sheet.ts": "import './index.scss'\n",
2177
+ "index.ts": "export * from './sheet.js'\n"
2178
+ }),
2179
+ themes: Object.freeze({
2180
+ "index.scss": "@use '../tokens';\n@use 'default';\n",
2181
+ "_default.scss": "",
2182
+ "sheet.ts": "import './index.scss'\n"
2183
+ }),
1881
2184
  empty: "",
2185
+ barrel: "// TODO: [Feature] Export the browser extension API.\n",
2186
+ main: `document.body
2187
+ .appendChild(document.createElement('main'))
2188
+ .appendChild(document.createElement('h1')).textContent ={{heading}}
2189
+ `,
2190
+ vue: Object.freeze({
2191
+ "main.ts": `import { createApp } from 'vue'
2192
+ import App from './App.vue'
2193
+
2194
+ createApp(App).mount(document.body.appendChild(document.createElement('main')))
2195
+ `,
2196
+ "App.vue": `<template>
2197
+ <h1>{{heading}}</h1>
2198
+ </template>
2199
+ `
2200
+ }),
1882
2201
  browser: `<!doctype html>
1883
2202
  <html lang="en">
1884
2203
  <head>
@@ -1893,9 +2212,263 @@ var ARTIFACT_TEMPLATES = Object.freeze({
1893
2212
  `
1894
2213
  }),
1895
2214
  tests: Object.freeze({
2215
+ journey: `import {
2216
+ ACCESSIBLE_ROLES,
2217
+ createPortfolio,
2218
+ expandCaptures,
2219
+ isRendered,
2220
+ readRefusal,
2221
+ readStyle,
2222
+ } from '@orkestrel/test/browser'
2223
+ {{imports}}import { page } from 'vitest/browser'
2224
+ import { describe, expect, inject, it } from 'vitest'
2225
+
2226
+ const VARIANT = inject('variant')
2227
+ const VARIANTS = inject('variants')
2228
+ const CAPTURE = inject('capture')
2229
+
2230
+ describe('{{application}} arrival journey', () => {
2231
+ it('proves the declared arrival families', async () => {
2232
+ const families = new Set(['Journey', 'Refusal', 'Matrix', ...(CAPTURE ? ['Capture'] : [])])
2233
+ const proven = new Set<string>()
2234
+ const states = ['{{application}}-arrival']
2235
+ const placed = new Set<string>()
2236
+ const portfolio = createPortfolio({
2237
+ states,
2238
+ variants: VARIANTS,
2239
+ variant: VARIANT,
2240
+ directory: '../../../tmp/captures/states',
2241
+ enabled: CAPTURE,
2242
+ })
2243
+ {{mount}} try {
2244
+ {{arrival}} const heading = page
2245
+ .getByRole('heading', {
2246
+ name: {{heading}},
2247
+ exact: true,
2248
+ level: 1,
2249
+ })
2250
+ .element()
2251
+ expect(isRendered(heading)).toBe(true)
2252
+ proven.add('Journey')
2253
+ await portfolio.place('{{application}}-arrival')
2254
+ placed.add('{{application}}-arrival')
2255
+
2256
+ for (const role of ACCESSIBLE_ROLES) expect(page.getByRole(role).elements()).toEqual([])
2257
+ expect(readRefusal('Continue')).toBe(
2258
+ 'No interactive element has the accessible name "Continue"',
2259
+ )
2260
+ proven.add('Refusal')
2261
+
2262
+ const measured = new Set<string>()
2263
+ for (const variant of VARIANTS) {
2264
+ await page.viewport(variant.width, variant.height)
2265
+ expect(readStyle(heading, 'display')).toBe('block')
2266
+ expect(window.innerWidth).toBe(variant.width)
2267
+ measured.add(variant.name)
2268
+ }
2269
+ expect(measured).toEqual(new Set(VARIANTS.map(({ name }) => name)))
2270
+ proven.add('Matrix')
2271
+
2272
+ const files = expandCaptures(states, VARIANTS)
2273
+ expect(portfolio.files).toEqual(files)
2274
+ expect(new Set(files).size).toBe(states.length * VARIANTS.length)
2275
+ expect(placed).toEqual(new Set(states))
2276
+ const expected = CAPTURE
2277
+ ? expandCaptures(
2278
+ states,
2279
+ VARIANTS.filter(({ name }) => name === VARIANT),
2280
+ )
2281
+ : []
2282
+ expect(portfolio.paths.map((path) => path.replaceAll('\\\\', '/').split('/').at(-1))).toEqual(
2283
+ expected,
2284
+ )
2285
+ if (CAPTURE) proven.add('Capture')
2286
+ expect(proven).toEqual(families)
2287
+ } finally {
2288
+ {{cleanup}} const variant = VARIANTS.find(({ name }) => name === VARIANT)
2289
+ if (variant !== undefined) await page.viewport(variant.width, variant.height)
2290
+ }
2291
+ })
2292
+ })
2293
+ `,
2294
+ browser: `import type { JourneyVariant } from '@orkestrel/test'
2295
+
2296
+ declare module 'vitest' {
2297
+ export interface ProvidedContext {
2298
+ readonly variant: string
2299
+ readonly variants: readonly JourneyVariant[]
2300
+ readonly capture: boolean
2301
+ }
2302
+ }
2303
+ `,
2304
+ sheet: `import sheet from '/dist/src/{{name}}/index.css?raw'
2305
+ import { describe, expect, it } from 'vitest'
2306
+ import { adoptSheet, readLayerNames } from '{{setup}}'
2307
+
2308
+ describe('{{name}} entry', () => {
2309
+ it('opens with the declared cascade order', () => {
2310
+ const adopted = adoptSheet(sheet)
2311
+ try {
2312
+ expect(adopted.sheet.cssRules[0]?.cssText).toBe(
2313
+ '@layer theme, reset, base, elements, components, utilities;',
2314
+ )
2315
+ expect(readLayerNames(adopted.sheet).slice(0, 6)).toEqual([
2316
+ 'theme',
2317
+ 'reset',
2318
+ 'base',
2319
+ 'elements',
2320
+ 'components',
2321
+ 'utilities',
2322
+ ])
2323
+ } finally {
2324
+ adopted.release()
2325
+ }
2326
+ })
2327
+ })
2328
+ `,
2329
+ styles: Object.freeze({
2330
+ module: `/** Carries a CSSOM rule and its enclosing layer. */
2331
+ export interface SheetEntry {
2332
+ readonly rule: CSSRule
2333
+ readonly layer: string | undefined
2334
+ }
2335
+
2336
+ /** Describes an adopted stylesheet and its idempotent release operation. */
2337
+ export interface SheetAdoption {
2338
+ readonly sheet: CSSStyleSheet
2339
+ release(): void
2340
+ }
2341
+
2342
+ /**
2343
+ * Adopts CSS text into the document with an idempotent release operation.
2344
+ * @param text - The compiled sheet text.
2345
+ * @returns The adopted sheet and its release operation.
2346
+ * @example
2347
+ * \`\`\`ts
2348
+ * const adopted = adoptSheet('.sample { color: red }')
2349
+ * adopted.release()
2350
+ * \`\`\`
2351
+ */
2352
+ export function adoptSheet(text: string): SheetAdoption {
2353
+ const sheet = new CSSStyleSheet()
2354
+ sheet.replaceSync(text)
2355
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]
2356
+ return {
2357
+ sheet,
2358
+ release: () => {
2359
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
2360
+ (candidate) => candidate !== sheet,
2361
+ )
2362
+ },
2363
+ }
2364
+ }
2365
+
2366
+ /**
2367
+ * Reads layer statements and blocks in declaration order, including repeated names.
2368
+ * @param sheet - The parsed sheet.
2369
+ * @returns Qualified layer names, with an empty name for an anonymous layer.
2370
+ * @example
2371
+ * \`\`\`ts
2372
+ * readLayerNames(new CSSStyleSheet()) // []
2373
+ * \`\`\`
2374
+ */
2375
+ export function readLayerNames(sheet: CSSStyleSheet): readonly string[] {
2376
+ const pending: SheetEntry[] = Array.from(sheet.cssRules, (rule) => ({
2377
+ rule,
2378
+ layer: undefined,
2379
+ })).reverse()
2380
+ const names: string[] = []
2381
+ while (pending.length > 0) {
2382
+ const entry = pending.pop()
2383
+ if (entry === undefined) break
2384
+ const { rule, layer } = entry
2385
+ const declared =
2386
+ rule instanceof CSSLayerStatementRule
2387
+ ? rule.nameList
2388
+ : rule instanceof CSSLayerBlockRule
2389
+ ? [rule.name]
2390
+ : []
2391
+ for (const name of declared) names.push(layer === undefined ? name : layer + '.' + name)
2392
+ if (!(rule instanceof CSSGroupingRule)) continue
2393
+ const parent =
2394
+ rule instanceof CSSLayerBlockRule
2395
+ ? layer === undefined
2396
+ ? rule.name
2397
+ : layer + '.' + rule.name
2398
+ : layer
2399
+ for (const child of Array.from(rule.cssRules).reverse()) {
2400
+ pending.push({ rule: child, layer: parent })
2401
+ }
2402
+ }
2403
+ return names
2404
+ }
2405
+ `,
2406
+ proof: `import type { SheetAdoption } from './setupStyles.js'
2407
+ import { describe, expect, it } from 'vitest'
2408
+ import { adoptSheet, readLayerNames } from './setupStyles.js'
2409
+
2410
+ describe('CSSOM instruments', () => {
2411
+ it('adopts and releases only its own sheet, including repeated release', () => {
2412
+ const previous = [...document.adoptedStyleSheets]
2413
+ const first: SheetAdoption = adoptSheet('.sample { color: red }')
2414
+ try {
2415
+ const second = adoptSheet('.other { display: block }')
2416
+ try {
2417
+ expect(document.adoptedStyleSheets).toEqual([...previous, first.sheet, second.sheet])
2418
+ expect(first.sheet.cssRules.length).toBe(1)
2419
+ first.release()
2420
+ first.release()
2421
+ expect(document.adoptedStyleSheets).toEqual([...previous, second.sheet])
2422
+ } finally {
2423
+ second.release()
2424
+ }
2425
+ } finally {
2426
+ first.release()
2427
+ }
2428
+ expect(document.adoptedStyleSheets).toEqual(previous)
2429
+ })
2430
+
2431
+ it('reads statements, blocks, nested conditions, and anonymous layers in order', () => {
2432
+ const adopted = adoptSheet(
2433
+ '@layer first, second; @layer first { @media all { @layer nested {} } } @layer {}',
2434
+ )
2435
+ try {
2436
+ expect(readLayerNames(adopted.sheet)).toEqual([
2437
+ 'first',
2438
+ 'second',
2439
+ 'first',
2440
+ 'first.nested',
2441
+ '',
2442
+ ])
2443
+ } finally {
2444
+ adopted.release()
2445
+ }
2446
+ })
2447
+
2448
+ it('returns no layer names for an empty sheet or an unlayered rule', () => {
2449
+ const sheet = new CSSStyleSheet()
2450
+ expect(readLayerNames(sheet)).toEqual([])
2451
+ sheet.replaceSync('.sample { color: red }')
2452
+ expect(readLayerNames(sheet)).toEqual([])
2453
+ })
2454
+ })
2455
+ `
2456
+ }),
1896
2457
  setup: "",
1897
- global: `export function setup(): void {}
2458
+ global: Object.freeze({
2459
+ module: `export function setup(): void {}
1898
2460
  `,
2461
+ proof: `import { describe, expect, it } from 'vitest'
2462
+ import { setup } from './setupGlobal.js'
2463
+
2464
+ describe('global setup', () => {
2465
+ it('runs without producing a teardown', () => {
2466
+ expect(setup()).toBeUndefined()
2467
+ expect(setup()).toBeUndefined()
2468
+ })
2469
+ })
2470
+ `
2471
+ }),
1899
2472
  entry: `import * as entry from {{specifier}}
1900
2473
  import { describe, expect, it } from 'vitest'
1901
2474
 
@@ -3255,6 +3828,80 @@ function isCollection(value) {
3255
3828
  */
3256
3829
  var isEnvironment = literalOf(ENVIRONMENTS);
3257
3830
  /**
3831
+ * Narrows a value to a surface an extension can extend.
3832
+ * @param value - The candidate surface.
3833
+ * @returns True if the value is a supported surface; false otherwise.
3834
+ * @example
3835
+ * ```ts
3836
+ * import { isSurface } from '@orkestrel/scaffold'
3837
+ *
3838
+ * isSurface('styles') // true
3839
+ * isSurface('themes') // false
3840
+ * ```
3841
+ */
3842
+ var isSurface = literalOf(SURFACES);
3843
+ /**
3844
+ * Narrows a value to a non-reserved sheet face name.
3845
+ * @param value - The candidate name.
3846
+ * @returns True if the name matches the workspace pattern and is not reserved; false otherwise.
3847
+ * @example
3848
+ * ```ts
3849
+ * import { isSheetName } from '@orkestrel/scaffold'
3850
+ *
3851
+ * isSheetName('print') // true
3852
+ * isSheetName('styles') // false
3853
+ * ```
3854
+ */
3855
+ function isSheetName(value) {
3856
+ return isString(value) && value.length <= 203 && NAME_PATTERN.test(value) && !RESERVED_SHEET_NAMES.includes(value);
3857
+ }
3858
+ /**
3859
+ * Narrows a value to a supported browser framework with distinct occupied axes.
3860
+ * @param value - The candidate extension.
3861
+ * @returns True if the value is an admitted extension; false otherwise.
3862
+ * @example
3863
+ * ```ts
3864
+ * import { isBrowserExtension } from '@orkestrel/scaffold'
3865
+ *
3866
+ * isBrowserExtension({ surface: 'browser', name: 'vue', axes: ['app'] }) // true
3867
+ * isBrowserExtension(undefined) // false
3868
+ * ```
3869
+ */
3870
+ var isBrowserExtension = andOf(recordOf({
3871
+ surface: literalOf("browser"),
3872
+ name: literalOf(FRAMEWORKS),
3873
+ axes: andOf(isCollection, arrayOf(literalOf(AXES)))
3874
+ }), (extension) => new Set(extension.axes).size === extension.axes.length);
3875
+ /**
3876
+ * Narrows a value to a named non-reserved stylesheet face.
3877
+ * @param value - The candidate extension.
3878
+ * @returns True if the value is an admitted extension; false otherwise.
3879
+ * @example
3880
+ * ```ts
3881
+ * import { isStylesExtension } from '@orkestrel/scaffold'
3882
+ *
3883
+ * isStylesExtension({ surface: 'styles', name: 'print' }) // true
3884
+ * isStylesExtension(undefined) // false
3885
+ * ```
3886
+ */
3887
+ var isStylesExtension = recordOf({
3888
+ surface: literalOf("styles"),
3889
+ name: isSheetName
3890
+ });
3891
+ /**
3892
+ * Narrows a value to an extension of a supported surface.
3893
+ * @param value - The candidate extension.
3894
+ * @returns True if the value is an admitted extension; false otherwise.
3895
+ * @example
3896
+ * ```ts
3897
+ * import { isExtension } from '@orkestrel/scaffold'
3898
+ *
3899
+ * isExtension({ surface: 'styles', name: 'print' }) // true
3900
+ * isExtension(undefined) // false
3901
+ * ```
3902
+ */
3903
+ var isExtension = unionOf(isBrowserExtension, isStylesExtension);
3904
+ /**
3258
3905
  * Narrows a value to one {@link Group} a plan selects over.
3259
3906
  *
3260
3907
  * @example
@@ -3391,6 +4038,9 @@ var isBlueprint = recordOf({
3391
4038
  keywords: andOf(isCollection, arrayOf(isString)),
3392
4039
  src: andOf(isCollection, arrayOf(isEnvironment)),
3393
4040
  app: andOf(isCollection, arrayOf(isEnvironment)),
4041
+ extensions: andOf(isCollection, arrayOf(isExtension)),
4042
+ styles: isBoolean,
4043
+ themes: isBoolean,
3394
4044
  dependencies: andOf(isCollection, arrayOf(isDependency)),
3395
4045
  peers: andOf(isCollection, arrayOf(isDependency)),
3396
4046
  extras: andOf(isCollection, arrayOf(isDependency)),
@@ -3685,6 +4335,34 @@ function cloneValue(value) {
3685
4335
  //#endregion
3686
4336
  //#region src/core/parsers.ts
3687
4337
  /**
4338
+ * Coerces an extension value or a `surface:name` selection into an extension.
4339
+ * @param value - An extension record or its selection text.
4340
+ * @returns The extension, or `undefined` for a malformed or unsupported selection.
4341
+ * @remarks Browser text has empty axes; the creating command supplies its selected browser axes.
4342
+ * @example
4343
+ * ```ts
4344
+ * import { parseExtension } from '@orkestrel/scaffold'
4345
+ *
4346
+ * parseExtension('browser:vue') // { surface: 'browser', name: 'vue', axes: [] }
4347
+ * parseExtension('styles:print') // { surface: 'styles', name: 'print' }
4348
+ * ```
4349
+ */
4350
+ function parseExtension(value) {
4351
+ if (isExtension(value)) return value;
4352
+ if (!isString(value)) return void 0;
4353
+ const [surface, name, excess] = value.split(":");
4354
+ if (excess !== void 0 || !isSurface(surface)) return void 0;
4355
+ const candidate = surface === "browser" ? {
4356
+ surface,
4357
+ name,
4358
+ axes: []
4359
+ } : {
4360
+ surface,
4361
+ name
4362
+ };
4363
+ return isExtension(candidate) ? candidate : void 0;
4364
+ }
4365
+ /**
3688
4366
  * Coerces an untrusted value to a {@link Blueprint}.
3689
4367
  *
3690
4368
  * @param value - The value to parse.
@@ -4770,6 +5448,67 @@ function renderSkillPointer(canonical, name) {
4770
5448
  //#endregion
4771
5449
  //#region src/core/compilers.ts
4772
5450
  /**
5451
+ * Projects a blueprint into browser extensions restricted to occupied browser axes.
5452
+ * @param blueprint - The workspace specification.
5453
+ * @returns Browser extensions with their occupied axes, omitting unplaced extensions.
5454
+ * @example
5455
+ * ```ts
5456
+ * import { blueprintToFaces, createBlueprint } from '@orkestrel/scaffold'
5457
+ *
5458
+ * blueprintToFaces(createBlueprint('desk', { app: ['core'] })).length // 0
5459
+ * ```
5460
+ */
5461
+ function blueprintToFaces(blueprint) {
5462
+ return blueprint.extensions.flatMap((extension) => {
5463
+ if (extension.surface !== "browser") return [];
5464
+ const axes = extension.axes.filter((axis) => blueprint[axis].includes("browser"));
5465
+ return axes.length === 0 ? [] : [{
5466
+ ...extension,
5467
+ axes
5468
+ }];
5469
+ });
5470
+ }
5471
+ /**
5472
+ * Projects a blueprint into its validated sheet-face names in stable order.
5473
+ * @param blueprint - The workspace specification.
5474
+ * @returns The base face followed by named styles extensions; themes remain a separate target.
5475
+ * @example
5476
+ * ```ts
5477
+ * import { blueprintToSheets, createBlueprint } from '@orkestrel/scaffold'
5478
+ *
5479
+ * blueprintToSheets(createBlueprint('paper', { styles: true })) // ['styles']
5480
+ * ```
5481
+ */
5482
+ function blueprintToSheets(blueprint) {
5483
+ return [...blueprint.styles ? ["styles"] : [], ...sortValues(blueprint.extensions.flatMap((extension) => extension.surface === "styles" && isSheetName(extension.name) ? [extension.name] : []))];
5484
+ }
5485
+ /**
5486
+ * Projects published environments and sheets into the manifest export map.
5487
+ * @param blueprint - The workspace specification.
5488
+ * @returns JavaScript conditions and CSS and SCSS subpaths, without an invented JavaScript root.
5489
+ * @example
5490
+ * ```ts
5491
+ * import { blueprintToExports, createBlueprint } from '@orkestrel/scaffold'
5492
+ *
5493
+ * blueprintToExports(createBlueprint('paper', { styles: true }))['./styles']
5494
+ * // './dist/src/styles/index.css'
5495
+ * ```
5496
+ */
5497
+ function blueprintToExports(blueprint) {
5498
+ const exports = { ...srcToExports(blueprint.src) };
5499
+ for (const extension of blueprintToFaces(blueprint)) {
5500
+ if (extension.surface !== "browser" || !extension.axes.includes("src")) continue;
5501
+ exports[`./${extension.name}`] = pathToCondition(`./dist/src/${extension.name}/index`, ["es"]);
5502
+ if (blueprint.src.includes("browser")) exports["./browser"] = pathToCondition("./dist/src/browser/index", ["es"]);
5503
+ }
5504
+ for (const name of [...blueprintToSheets(blueprint), ...blueprint.themes ? ["styles/themes"] : []]) {
5505
+ exports[`./${name}`] = `./dist/src/${name}/index.css`;
5506
+ exports[`./${name}/scss`] = `./src/${name}/index.scss`;
5507
+ }
5508
+ if (Object.keys(exports).length > 0) exports["./package.json"] = "./package.json";
5509
+ return exports;
5510
+ }
5511
+ /**
4773
5512
  * Builds one `exports` condition block for a built environment.
4774
5513
  *
4775
5514
  * @param path - The extensionless `dist` path both conditions point at.
@@ -4916,18 +5655,21 @@ function srcToExports(src) {
4916
5655
  * ```
4917
5656
  */
4918
5657
  function blueprintToDevDependencies(blueprint) {
5658
+ const sheets = blueprintToSheets(blueprint).length > 0 || blueprint.themes;
4919
5659
  const merged = {
4920
5660
  ...BASE_DEV_DEPENDENCIES,
5661
+ ...sheets ? STYLES_DEV_DEPENDENCIES : {},
4921
5662
  ...blueprint.src.length > 0 || blueprint.bin ? DECLARATION_DEV_DEPENDENCIES : {},
4922
- ...blueprint.src.includes("browser") || blueprint.setup.includes("browser") ? SOURCE_BROWSER_DEV_DEPENDENCIES : {},
5663
+ ...blueprint.src.includes("browser") || blueprint.setup.includes("browser") || sheets ? SOURCE_BROWSER_DEV_DEPENDENCIES : {},
4923
5664
  ...blueprint.app.length > 0 ? APP_DEV_DEPENDENCIES : {},
4924
5665
  ...blueprint.app.includes("browser") ? APP_BROWSER_DEV_DEPENDENCIES : {},
4925
5666
  ...blueprint.showcase && blueprint.app.includes("browser") ? SHOWCASE_DEV_DEPENDENCIES : {},
4926
5667
  ...blueprint.app.includes("server") ? APP_SERVER_DEV_DEPENDENCIES : {}
4927
5668
  };
5669
+ for (const framework of blueprintToMachinery(blueprint).frameworks) Object.assign(merged, FRAMEWORK_MATRIX[framework].dependencies);
4928
5670
  for (const extra of blueprint.extras) merged[extra.name] = extra.range;
4929
5671
  for (const peer of blueprint.peers) if (!Object.hasOwn(merged, peer.name)) merged[peer.name] = peer.range;
4930
- const own = blueprint.src.length > 0 ? `@orkestrel/${blueprint.name}` : blueprint.name;
5672
+ const own = blueprint.src.length > 0 || sheets ? `@orkestrel/${blueprint.name}` : blueprint.name;
4931
5673
  const runtime = new Set(blueprint.dependencies.map((dependency) => dependency.name));
4932
5674
  return Object.fromEntries(Object.entries(merged).filter(([name]) => name !== own && !runtime.has(name)).sort(([left], [right]) => compareValues(left, right)));
4933
5675
  }
@@ -4968,11 +5710,22 @@ function blueprintToDevDependencies(blueprint) {
4968
5710
  * ```
4969
5711
  */
4970
5712
  function blueprintToScripts(blueprint) {
4971
- const publishes = blueprint.src.length > 0;
5713
+ const source = blueprintToFaces(blueprint).flatMap((extension) => extension.surface === "browser" && extension.axes.includes("src") ? [extension.name] : []);
5714
+ const application = blueprintToFaces(blueprint).flatMap((extension) => extension.surface === "browser" && extension.axes.includes("app") ? [extension.name] : []);
5715
+ const sheets = blueprintToSheets(blueprint);
5716
+ const targets = [...sheets, ...blueprint.themes && !blueprint.styles ? ["themes"] : []];
5717
+ const checker = application.includes("vue") ? FRAMEWORK_MATRIX.vue.checker : "tsc";
5718
+ const publishes = blueprint.src.length > 0 || targets.length > 0;
4972
5719
  const integrates = blueprint.integration;
4973
5720
  const compiles = publishes || blueprint.bin;
4974
5721
  const runtime = blueprint.app.filter((environment) => environment !== "core");
4975
5722
  const vitest = "vitest run --config vite.config.ts --no-cache --reporter=dot";
5723
+ const checks = [
5724
+ ...blueprint.src,
5725
+ ...source,
5726
+ ...sheets,
5727
+ ...blueprint.bin ? ["bin"] : []
5728
+ ].map((name) => `npm run check:src:${name}`);
4976
5729
  const scripts = {
4977
5730
  clean: "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
4978
5731
  copy: "node -e \"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\"",
@@ -4981,30 +5734,32 @@ function blueprintToScripts(blueprint) {
4981
5734
  lint: "oxlint --config .oxlintrc.json --fix .",
4982
5735
  "lint:check": "oxlint --config .oxlintrc.json --deny-warnings .",
4983
5736
  check: [
4984
- "tsc --noEmit --project tsconfig.json",
4985
- ...compiles ? ["npm run check:src"] : [],
5737
+ `${checker} --noEmit --project tsconfig.json`,
5738
+ ...checks.length > 0 ? ["npm run check:src"] : [],
4986
5739
  ...blueprint.app.length > 0 ? ["npm run check:app"] : [],
4987
5740
  ...blueprint.skills ? ["npm run check:skills"] : []
4988
5741
  ].join(" && ")
4989
5742
  };
4990
- if (compiles) {
4991
- scripts["check:src"] = [...blueprint.src.map((environment) => `npm run check:src:${environment}`), ...blueprint.bin ? ["npm run check:src:bin"] : []].join(" && ");
5743
+ if (checks.length > 0) {
5744
+ scripts["check:src"] = checks.join(" && ");
4992
5745
  for (const environment of blueprint.src) scripts[`check:src:${environment}`] = `tsc --noEmit -p configs/src/tsconfig.${environment}.json`;
4993
5746
  if (blueprint.bin) scripts["check:src:bin"] = "tsc --noEmit -p configs/src/tsconfig.bin.json";
5747
+ for (const name of [...sheets, ...source]) scripts[`check:src:${name}`] = `tsc --noEmit -p configs/src/tsconfig.${name}.json`;
4994
5748
  }
4995
5749
  if (blueprint.app.length > 0) {
4996
- scripts["check:app"] = blueprint.app.map((environment) => `npm run check:app:${environment}`).join(" && ");
4997
- for (const environment of blueprint.app) scripts[`check:app:${environment}`] = environment === "browser" ? "vue-tsc --noEmit -p configs/app/tsconfig.browser.json" : `tsc --noEmit -p configs/app/tsconfig.${environment}.json`;
5750
+ scripts["check:app"] = [...blueprint.app, ...application].map((environment) => `npm run check:app:${environment}`).join(" && ");
5751
+ for (const environment of blueprint.app) scripts[`check:app:${environment}`] = `tsc --noEmit -p configs/app/tsconfig.${environment}.json`;
5752
+ for (const name of application) scripts[`check:app:${name}`] = `${FRAMEWORK_MATRIX[name].checker} --noEmit -p configs/app/tsconfig.${name}.json`;
4998
5753
  }
4999
5754
  if (blueprint.skills) scripts["check:skills"] = `tsc --noEmit -p ${SKILLS_CONFIG_PATH}`;
5000
5755
  scripts.test = [
5001
5756
  ...compiles ? ["npm run test:src"] : [],
5002
5757
  ...blueprint.app.length > 0 ? ["npm run test:app"] : [],
5003
- ...blueprint.journey && blueprint.app.includes("browser") ? ["npm run test:journey"] : [],
5758
+ ...blueprint.journey && blueprint.app.includes("browser") ? ["npm run test:journey", ...application.map((name) => `npm run test:journey:${name}`)] : [],
5004
5759
  "npm run test:policy",
5005
5760
  "npm run test:config",
5006
- ...blueprint.setup.includes("node") ? ["npm run test:setup"] : [],
5007
- ...blueprint.setup.includes("browser") ? ["npm run test:setup:browser"] : [],
5761
+ ...blueprint.setup.includes("node") || blueprint.global ? ["npm run test:setup"] : [],
5762
+ ...blueprint.setup.includes("browser") || targets.length > 0 ? ["npm run test:setup:browser"] : [],
5008
5763
  ...blueprint.skills ? ["npm run test:skills"] : [],
5009
5764
  ...blueprint.guides ? ["npm run test:guides"] : [],
5010
5765
  ...blueprint.conformance ? ["npm run test:conformance"] : [],
@@ -5015,20 +5770,32 @@ function blueprintToScripts(blueprint) {
5015
5770
  scripts["test:src"] = [
5016
5771
  vitest,
5017
5772
  ...blueprint.src.map((environment) => `--project ${SRC_MATRIX[environment].project}`),
5773
+ ...source.map((name) => `--project src:${name}`),
5018
5774
  ...blueprint.bin ? ["--project src:bin"] : []
5019
5775
  ].join(" ");
5020
5776
  for (const environment of blueprint.src) scripts[`test:src:${environment}`] = `${vitest} --project ${SRC_MATRIX[environment].project}`;
5021
5777
  if (blueprint.bin) scripts["test:src:bin"] = `${vitest} --project src:bin`;
5778
+ for (const name of source) scripts[`test:src:${name}`] = `${vitest} --project src:${name}`;
5779
+ scripts["test:src"] = [...blueprint.src.length > 0 || blueprint.bin ? [scripts["test:src"]] : [], ...targets.map((name) => `npm run test:src:${name}`)].join(" && ");
5780
+ for (const name of targets) scripts[`test:src:${name}`] = `npm run build:src:${name} && ${vitest} --project src:${name}`;
5022
5781
  }
5023
5782
  if (blueprint.app.length > 0) {
5024
- scripts["test:app"] = [vitest, ...blueprint.app.map((environment) => `--project ${APP_MATRIX[environment].project}`)].join(" ");
5783
+ scripts["test:app"] = [
5784
+ vitest,
5785
+ ...blueprint.app.map((environment) => `--project ${APP_MATRIX[environment].project}`),
5786
+ ...application.map((name) => `--project app:${name}`)
5787
+ ].join(" ");
5025
5788
  for (const environment of blueprint.app) scripts[`test:app:${environment}`] = `${vitest} --project ${APP_MATRIX[environment].project}`;
5789
+ for (const name of application) scripts[`test:app:${name}`] = `${vitest} --project app:${name}`;
5026
5790
  }
5027
5791
  scripts["test:policy"] = `${vitest} --project policy`;
5028
5792
  scripts["test:config"] = `${vitest} --project config`;
5029
- if (blueprint.setup.includes("node")) scripts["test:setup"] = `${vitest} --project setup`;
5030
- if (blueprint.setup.includes("browser")) scripts["test:setup:browser"] = `${vitest} --project setup:browser`;
5031
- if (blueprint.journey && blueprint.app.includes("browser")) scripts["test:journey"] = `vitest run --config ${JOURNEY_CONFIG_PATH} --no-cache --reporter=dot`;
5793
+ if (blueprint.setup.includes("node") || blueprint.global) scripts["test:setup"] = `${vitest} --project setup`;
5794
+ if (blueprint.setup.includes("browser") || targets.length > 0) scripts["test:setup:browser"] = `${vitest} --project setup:browser`;
5795
+ if (blueprint.journey && blueprint.app.includes("browser")) {
5796
+ scripts["test:journey"] = `vitest run --config ${JOURNEY_CONFIG_PATH} --no-cache --reporter=dot`;
5797
+ for (const name of application) scripts[`test:journey:${name}`] = `${scripts["test:journey"]} --mode ${name}`;
5798
+ }
5032
5799
  if (blueprint.skills) scripts["test:skills"] = `${vitest} --project skills`;
5033
5800
  if (blueprint.guides) scripts["test:guides"] = `node --experimental-strip-types ${GUIDES_TEST_PATH}`;
5034
5801
  if (blueprint.conformance) scripts["test:conformance"] = `${vitest} --project conformance`;
@@ -5043,23 +5810,34 @@ function blueprintToScripts(blueprint) {
5043
5810
  ...blueprint.app.length > 0 ? ["npm run build:app"] : []
5044
5811
  ].join(" && ");
5045
5812
  if (compiles) {
5046
- scripts["build:src"] = [...blueprint.src.map((environment) => `npm run build:src:${environment}`), ...blueprint.bin ? ["npm run build:src:bin"] : []].join(" && ");
5813
+ scripts["build:src"] = [
5814
+ ...blueprint.src.map((environment) => `npm run build:src:${environment}`),
5815
+ ...source.map((name) => `npm run build:src:${name}`),
5816
+ ...targets.map((name) => `npm run build:src:${name}`),
5817
+ ...blueprint.bin ? ["npm run build:src:bin"] : []
5818
+ ].join(" && ");
5047
5819
  for (const environment of blueprint.src) {
5048
5820
  const build = `vite build --config configs/src/vite.${environment}.config.ts`;
5049
5821
  scripts[`build:src:${environment}`] = SRC_MATRIX[environment].formats.includes("cjs") ? `${build} && npm run copy dist/src/${environment}/index.d.ts dist/src/${environment}/index.d.cts` : build;
5050
5822
  }
5051
5823
  if (blueprint.bin) scripts["build:src:bin"] = "vite build --config configs/src/vite.bin.config.ts";
5824
+ for (const name of source) scripts[`build:src:${name}`] = `vite build --config configs/src/vite.${name}.config.ts`;
5825
+ for (const name of targets) scripts[`build:src:${name}`] = [`vite build --config configs/src/vite.${name}.config.ts`, ...name === "styles" && blueprint.themes ? ["vite build --config configs/src/vite.themes.config.ts"] : []].join(" && ");
5052
5826
  }
5053
5827
  if (blueprint.app.length > 0) {
5054
- scripts["build:app"] = runtime.length > 0 ? runtime.map((environment) => `npm run build:app:${environment}`).join(" && ") : "npm run check:app:core";
5055
- for (const environment of runtime) scripts[`build:app:${environment}`] = `vite build --config configs/app/vite.${environment}.config.ts`;
5828
+ scripts["build:app"] = runtime.length > 0 ? [...runtime, ...application].map((environment) => `npm run build:app:${environment}`).join(" && ") : "npm run check:app:core";
5829
+ for (const environment of [...runtime, ...application]) scripts[`build:app:${environment}`] = `vite build --config configs/app/vite.${environment}.config.ts`;
5056
5830
  }
5057
5831
  if (blueprint.app.includes("browser")) {
5058
5832
  scripts.dev = "vite --config configs/app/vite.browser.config.ts";
5833
+ for (const name of application) scripts[`dev:${name}`] = `vite --config configs/app/vite.${name}.config.ts`;
5059
5834
  if (blueprint.showcase) {
5060
5835
  scripts.showcase = `vite --config ${SHOWCASE_CONFIG_PATH}`;
5061
5836
  scripts["build:showcase"] = `vite build --config ${SHOWCASE_CONFIG_PATH}`;
5062
- scripts.show = "npm run format && npm run build:showcase && npm run copy dist/showcase/index.html demo/showcase.html";
5837
+ for (const name of application) {
5838
+ scripts[`showcase:${name}`] = `${scripts.showcase} --mode ${name}`;
5839
+ scripts[`build:showcase:${name}`] = `${scripts["build:showcase"]} --mode ${name}`;
5840
+ }
5063
5841
  }
5064
5842
  }
5065
5843
  if (blueprint.app.includes("server")) {
@@ -5069,7 +5847,9 @@ function blueprintToScripts(blueprint) {
5069
5847
  if (publishes) {
5070
5848
  scripts.prepack = "npm run build";
5071
5849
  scripts.prepublishOnly = [
5072
- "npm run format:check && npm run lint:check && npm run check && npm run build && npm test",
5850
+ "npm run format:check && npm run lint:check && npm run check && npm run build",
5851
+ ...blueprint.showcase && blueprint.app.includes("browser") ? ["npm run build:showcase", ...application.map((name) => `npm run build:showcase:${name}`)] : [],
5852
+ "npm test",
5073
5853
  RELEASE_PROOF_COMMAND,
5074
5854
  ...blueprint.service ? ["npm run test:service"] : []
5075
5855
  ].join(" && ");
@@ -5087,6 +5867,8 @@ function blueprintToScripts(blueprint) {
5087
5867
  * benchmark workbench scripts. A workspace carrying guides adds `test:guides`,
5088
5868
  * whose package-owned entry runs the guides project and handles explicit parity
5089
5869
  * rewrites, and one carrying skills adds `test:skills`. Publishing adds the pack and publication lifecycle scripts.
5870
+ * Sheet and framework faces add their check and build scripts, application frameworks add dev scripts,
5871
+ * and selected showcases and journeys add their mode scripts.
5090
5872
  * Aggregate test scripts and
5091
5873
  * maintainer-owned gate chains stay outside the region.
5092
5874
  *
@@ -5110,13 +5892,18 @@ function blueprintToScripts(blueprint) {
5110
5892
  */
5111
5893
  function blueprintToWritableScripts(blueprint) {
5112
5894
  const scripts = blueprintToScripts(blueprint);
5895
+ const sheets = [...blueprintToSheets(blueprint), ...blueprint.themes && !blueprint.styles ? ["themes"] : []];
5113
5896
  const writable = [];
5114
5897
  for (const [name, command] of Object.entries(scripts)) {
5115
- if (!(name.startsWith("test:") && name !== "test:src" && name !== "test:app")) continue;
5898
+ const direct = name.startsWith("test:") && name !== "test:src" && name !== "test:app";
5899
+ const sheet = sheets.some((face) => name === `build:src:${face}` || name === `check:src:${face}`);
5900
+ const framework = blueprintToFaces(blueprint).some((extension) => extension.surface === "browser" && extension.axes.some((axis) => name === `check:${axis}:${extension.name}` || name === `build:${axis}:${extension.name}` || axis === "app" && name === `dev:${extension.name}`));
5901
+ const showcase = name === "showcase" || name.startsWith("showcase:") || name === "build:showcase" || name.startsWith("build:showcase:");
5902
+ if (!direct && !sheet && !framework && !showcase) continue;
5116
5903
  writable.push({
5117
5904
  name,
5118
5905
  command,
5119
- accepted: name === "test:guides" ? ["vitest run --config vite.config.ts --no-cache --reporter=dot --project guides"] : []
5906
+ accepted: name === "test:guides" ? ["vitest run --config vite.config.ts --no-cache --reporter=dot --project guides"] : name === "build:src:styles" && blueprint.themes ? ["vite build --config configs/src/vite.styles.config.ts"] : sheets.some((face) => name === `test:src:${face}`) ? [command.slice(command.indexOf(" && ") + 4)] : []
5120
5907
  });
5121
5908
  }
5122
5909
  const prepack = scripts.prepack;
@@ -5172,7 +5959,9 @@ function blueprintToWritableScripts(blueprint) {
5172
5959
  * ```
5173
5960
  */
5174
5961
  function blueprintToManifest(blueprint) {
5175
- const publishes = blueprint.src.length > 0;
5962
+ const sheets = blueprintToSheets(blueprint);
5963
+ const targets = [...sheets, ...blueprint.themes ? ["styles/themes"] : []];
5964
+ const publishes = blueprint.src.length > 0 || targets.length > 0;
5176
5965
  const name = publishes ? `@orkestrel/${blueprint.name}` : blueprint.name;
5177
5966
  const dependencies = {};
5178
5967
  for (const dependency of [...blueprint.dependencies].sort((left, right) => compareValues(left.name, right.name))) dependencies[dependency.name] = dependency.range;
@@ -5199,18 +5988,19 @@ function blueprintToManifest(blueprint) {
5199
5988
  url: `git+https://github.com/orkestrel/${blueprint.name}.git`
5200
5989
  } } : {},
5201
5990
  ...blueprint.bin ? { bin: { [blueprint.name]: "./dist/bin/main.js" } } : {},
5202
- files: blueprint.bin ? [
5203
- "dist/src",
5204
- "dist/bin",
5991
+ files: [
5992
+ blueprint.bin || publishes ? "dist/src" : "dist/app",
5993
+ ...blueprint.bin ? ["dist/bin"] : [],
5994
+ ...targets.map((face) => `!dist/src/${face}/index.js`),
5995
+ ...sheets.map((face) => `src/${face}/**/*.scss`),
5996
+ ...blueprint.themes && !blueprint.styles ? ["src/styles/themes/**/*.scss"] : [],
5205
5997
  "README.md"
5206
- ] : publishes ? ["dist/src", "README.md"] : ["dist/app", "README.md"],
5998
+ ],
5207
5999
  type: "module",
5208
6000
  ...publishes ? {
5209
- sideEffects: blueprint.bin ? [`./${BIN_ENTRY_PATH}`, "./dist/bin/main.js"] : false,
5210
- main: entry.main,
5211
- module: entry.module,
5212
- ...entry.types === void 0 ? {} : { types: entry.types },
5213
- exports: srcToExports(blueprint.src),
6001
+ sideEffects: targets.length > 0 || blueprint.bin ? [...targets.length > 0 ? ["**/*.css", "**/*.scss"] : [], ...blueprint.bin ? [`./${BIN_ENTRY_PATH}`, "./dist/bin/main.js"] : []] : false,
6002
+ ...blueprint.src.length > 0 ? entry : {},
6003
+ exports: blueprintToExports(blueprint),
5214
6004
  publishConfig: { access: "public" }
5215
6005
  } : {},
5216
6006
  scripts: blueprintToScripts(blueprint),
@@ -5247,15 +6037,16 @@ function blueprintToManifest(blueprint) {
5247
6037
  *
5248
6038
  * const blueprint = createBlueprint('router', { app: ['browser'] })
5249
6039
  *
5250
- * blueprintToMachinery(blueprint).vue // true
6040
+ * blueprintToMachinery(blueprint).frameworks // []
5251
6041
  * ```
5252
6042
  */
5253
6043
  function blueprintToMachinery(blueprint) {
5254
6044
  const hosted = blueprint.app.some((environment) => environment !== "core");
6045
+ const frameworks = FRAMEWORKS.filter((framework) => blueprintToFaces(blueprint).some((extension) => extension.surface === "browser" && extension.name === framework && extension.axes.some((axis) => blueprint[axis].includes("browser"))));
5255
6046
  return {
5256
- browser: blueprint.src.includes("browser") || blueprint.app.includes("browser") || blueprint.setup.includes("browser"),
5257
- vue: blueprint.app.includes("browser"),
5258
- output: blueprint.src.length > 0 || blueprint.bin || hosted,
6047
+ browser: blueprint.src.includes("browser") || blueprint.app.includes("browser") || blueprint.setup.includes("browser") || blueprintToSheets(blueprint).length > 0 || blueprint.themes || frameworks.length > 0,
6048
+ frameworks,
6049
+ output: blueprint.src.length > 0 || blueprint.bin || hosted || blueprintToSheets(blueprint).length > 0 || blueprint.themes,
5259
6050
  showcase: blueprint.showcase && blueprint.app.includes("browser")
5260
6051
  };
5261
6052
  }
@@ -5291,6 +6082,12 @@ function blueprintToMachinery(blueprint) {
5291
6082
  */
5292
6083
  function blueprintToRootTsconfig(blueprint) {
5293
6084
  const aliases = [];
6085
+ for (const extension of blueprintToFaces(blueprint)) {
6086
+ if (extension.surface !== "browser") continue;
6087
+ for (const axis of extension.axes) aliases.push([`@${axis}/${extension.name}`, `./${axis}/${extension.name}/index.ts`]);
6088
+ if (extension.axes.includes("src")) aliases.push([`@orkestrel/${blueprint.name}/${extension.name}`, `./src/${extension.name}/index.ts`]);
6089
+ }
6090
+ for (const name of blueprintToSheets(blueprint)) aliases.push([`@src/${name}`, `./src/${name}/index.ts`]);
5294
6091
  for (const environment of ENVIRONMENTS) if (blueprint.src.includes(environment)) aliases.push([`@src/${environment}`, `./src/${environment}/index.ts`]);
5295
6092
  for (const environment of ENVIRONMENTS) if (blueprint.app.includes(environment)) aliases.push([`@app/${environment}`, `./app/${environment}/index.ts`]);
5296
6093
  const root = srcToRoot(blueprint.src);
@@ -5306,7 +6103,47 @@ function blueprintToRootTsconfig(blueprint) {
5306
6103
  if (matchesPrintWidth(line)) return line;
5307
6104
  return `\t\t\t"${specifier}": [\n\t\t\t\t"${target}"\n\t\t\t]${separator}`;
5308
6105
  }).join("\n");
5309
- return fillTemplate(CONFIG_TEMPLATES.root.tsconfig, { paths });
6106
+ return fillTemplate(CONFIG_TEMPLATES.root.tsconfig, { paths: aliases.length === 0 ? " \"paths\": {}" : `\t\t"paths": {\n${paths}\n\t\t}` });
6107
+ }
6108
+ /**
6109
+ * Projects a blueprint into the project labels its root Vitest configuration registers.
6110
+ *
6111
+ * @param blueprint - The workspace specification.
6112
+ * @returns Project labels in registration order, including wrapper-registered sheet faces.
6113
+ *
6114
+ * @example
6115
+ * ```ts
6116
+ * import { blueprintToProjects, createBlueprint } from '@orkestrel/scaffold'
6117
+ *
6118
+ * blueprintToProjects(createBlueprint('desk')).includes('policy') // true
6119
+ * ```
6120
+ */
6121
+ function blueprintToProjects(blueprint) {
6122
+ const sheets = blueprintToSheets(blueprint);
6123
+ const styled = sheets.length > 0 || blueprint.themes;
6124
+ const faces = blueprintToFaces(blueprint);
6125
+ const projects = sheets.map((name) => `src:${name}`);
6126
+ if (blueprint.themes && !blueprint.styles) projects.push("src:themes");
6127
+ for (const axis of AXES) {
6128
+ for (const environment of ENVIRONMENTS) {
6129
+ if (axis === "app" && environment === "server") continue;
6130
+ if (blueprint[axis].includes(environment)) projects.push(`${axis}:${environment}`);
6131
+ }
6132
+ for (const face of faces) if (face.surface === "browser" && face.axes.includes(axis)) projects.push(`${axis}:${face.name}`);
6133
+ if (axis === "src" && blueprint.bin) projects.push("src:bin");
6134
+ if (axis === "app" && blueprint.app.includes("server")) projects.push("app:server");
6135
+ }
6136
+ projects.push("policy", "config");
6137
+ if (blueprint.setup.includes("node") || blueprint.global) projects.push("setup");
6138
+ if (blueprint.setup.includes("browser") || styled) projects.push("setup:browser");
6139
+ if (blueprint.guides) projects.push("guides");
6140
+ if (blueprint.skills) projects.push("skills");
6141
+ if (blueprint.conformance) projects.push("conformance");
6142
+ if (blueprint.service) projects.push("service");
6143
+ if (blueprint.src.length > 0 || styled) projects.push("distribution");
6144
+ if (blueprint.integration) projects.push("integration");
6145
+ projects.push("probe");
6146
+ return projects;
5310
6147
  }
5311
6148
  /**
5312
6149
  * Compiles the root Vite and Vitest configuration for a blueprint.
@@ -5330,44 +6167,58 @@ function blueprintToRootTsconfig(blueprint) {
5330
6167
  */
5331
6168
  function blueprintToRootVite(blueprint) {
5332
6169
  const machinery = blueprintToMachinery(blueprint);
5333
- const publishes = blueprint.src.length > 0;
6170
+ const planned = new Set(blueprintToProjects(blueprint));
6171
+ const sheets = blueprintToSheets(blueprint);
6172
+ const styled = sheets.length > 0 || blueprint.themes;
5334
6173
  const global = blueprint.global ? " globalSetup: ['./tests/setupGlobal.ts'],\n" : "";
5335
6174
  const imports = [];
5336
6175
  if (machinery.browser) imports.push("import { playwright } from '@vitest/browser-playwright'");
5337
- if (machinery.vue) imports.push("import vue from '@vitejs/plugin-vue'");
6176
+ if (machinery.frameworks.includes("vue")) imports.push("import vue from '@vitejs/plugin-vue'");
5338
6177
  if (machinery.showcase) imports.push("import { viteSingleFile } from 'vite-plugin-singlefile'");
6178
+ if (machinery.showcase) {
6179
+ imports.push("import { renameSync } from 'node:fs'");
6180
+ imports.push("import { resolve as resolvePath } from 'node:path'");
6181
+ }
5339
6182
  const factories = [];
5340
6183
  const projects = [];
5341
- if (blueprint.src.includes("core")) {
6184
+ const external = "external: resolveSourceExternal,";
6185
+ if (blueprint.src.includes("browser") || blueprint.src.includes("server")) factories.push(blueprint.src.includes("core") ? `function resolveSourceExternal(id: string): boolean {
6186
+ return (
6187
+ id === '@src/core' ||
6188
+ resolveExternal(id, {
6189
+ peers,
6190
+ refused: [],
6191
+ siblings: [resolveWorkspacePath('src/core/index.ts')],
6192
+ })
6193
+ )
6194
+ }
6195
+ ` : `function resolveSourceExternal(id: string): boolean {
6196
+ return resolveExternal(id, { peers, refused: [], siblings: [] })
6197
+ }
6198
+ `);
6199
+ if (styled) {
6200
+ factories.push(CONFIG_TEMPLATES.factories.sheet);
6201
+ for (const name of sheets) projects.push(`'./configs/src/vite.${name}.config.ts'`);
6202
+ if (planned.has("src:themes")) projects.push("'./configs/src/vite.themes.config.ts'");
6203
+ }
6204
+ if (planned.has("src:core")) {
5342
6205
  factories.push(CONFIG_TEMPLATES.factories.src.core);
5343
6206
  projects.push("srcCore");
5344
6207
  }
5345
- if (blueprint.src.includes("browser")) {
6208
+ if (planned.has("src:browser")) {
5346
6209
  const core = blueprint.src.includes("core");
5347
6210
  factories.push(fillTemplate(CONFIG_TEMPLATES.factories.src.browser, {
5348
- external: core ? `external: (id: string) =>
5349
- id === '@src/core' ||
5350
- id.startsWith('@orkestrel/') ||
5351
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
5352
- id.startsWith('@orkestrel/') ||
5353
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
6211
+ external,
5354
6212
  output: core ? " output: { paths: { '@src/core': '../core/index.js' } }," : " output: {},",
5355
6213
  exclude: core ? " exclude: ['tests/src/core/**/*.test.ts'],\n" : "",
5356
6214
  global
5357
6215
  }));
5358
6216
  projects.push("srcBrowser");
5359
6217
  }
5360
- if (blueprint.src.includes("server")) {
6218
+ if (planned.has("src:server")) {
5361
6219
  const core = blueprint.src.includes("core");
5362
6220
  factories.push(fillTemplate(CONFIG_TEMPLATES.factories.src.server, {
5363
- external: core ? `external: (id: string) =>
5364
- id === '@src/core' ||
5365
- id.startsWith('node:') ||
5366
- id.startsWith('@orkestrel/') ||
5367
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),` : `external: (id: string) =>
5368
- id.startsWith('node:') ||
5369
- id.startsWith('@orkestrel/') ||
5370
- peers.some((peer) => id === peer || id.startsWith(peer + '/')),`,
6221
+ external,
5371
6222
  output: core ? `\t\t\t\toutput: [
5372
6223
  {
5373
6224
  format: 'es',
@@ -5384,15 +6235,19 @@ function blueprintToRootVite(blueprint) {
5384
6235
  }));
5385
6236
  projects.push("srcServer");
5386
6237
  }
5387
- if (blueprint.bin) {
6238
+ if (planned.has("src:vue")) {
6239
+ factories.push(CONFIG_TEMPLATES.factories.src.vue);
6240
+ projects.push("srcVue");
6241
+ }
6242
+ if (planned.has("src:bin")) {
5388
6243
  factories.push(CONFIG_TEMPLATES.factories.src.bin);
5389
6244
  projects.push("srcBin");
5390
6245
  }
5391
- if (blueprint.app.includes("core")) {
6246
+ if (planned.has("app:core")) {
5392
6247
  factories.push(CONFIG_TEMPLATES.factories.app.core);
5393
6248
  projects.push("appCore");
5394
6249
  }
5395
- if (blueprint.app.includes("browser")) {
6250
+ if (planned.has("app:browser")) {
5396
6251
  const showcaseFactory = machinery.showcase ? CONFIG_TEMPLATES.factories.app.showcase : "";
5397
6252
  factories.push(fillTemplate(CONFIG_TEMPLATES.factories.app.browser, {
5398
6253
  showcaseFactory,
@@ -5401,7 +6256,11 @@ function blueprintToRootVite(blueprint) {
5401
6256
  }));
5402
6257
  projects.push("appBrowser");
5403
6258
  }
5404
- if (blueprint.app.includes("server")) {
6259
+ if (planned.has("app:vue")) {
6260
+ factories.push(fillTemplate(CONFIG_TEMPLATES.factories.app.vue, { journeyExclude: blueprint.journey ? " exclude: ['tests/app/vue/integration.test.ts'],\n" : " exclude: [],\n" }));
6261
+ projects.push("appVue");
6262
+ }
6263
+ if (planned.has("app:server")) {
5405
6264
  factories.push(CONFIG_TEMPLATES.factories.app.server);
5406
6265
  projects.push("appServer");
5407
6266
  }
@@ -5409,39 +6268,40 @@ function blueprintToRootVite(blueprint) {
5409
6268
  projects.push("policy");
5410
6269
  factories.push(CONFIG_TEMPLATES.factories.config);
5411
6270
  projects.push("config");
5412
- if (blueprint.setup.includes("node")) {
6271
+ if (planned.has("setup")) {
5413
6272
  factories.push(CONFIG_TEMPLATES.factories.setup);
5414
6273
  projects.push("setup");
5415
6274
  }
5416
- if (blueprint.setup.includes("browser")) {
6275
+ if (planned.has("setup:browser")) {
5417
6276
  factories.push(fillTemplate(CONFIG_TEMPLATES.factories.browser, {
5418
- plugins: machinery.vue ? " plugins: [vue()],\n" : "",
6277
+ optimization: machinery.frameworks.includes("vue") ? "optimizeDeps: { include: [...optimizeDeps.include, 'vue'] }" : "optimizeDeps",
6278
+ plugins: machinery.frameworks.includes("vue") ? " plugins: [vue()],\n" : "",
5419
6279
  global
5420
6280
  }));
5421
6281
  projects.push("setupBrowser");
5422
6282
  }
5423
- if (blueprint.guides) {
6283
+ if (planned.has("guides")) {
5424
6284
  factories.push(CONFIG_TEMPLATES.factories.guides);
5425
6285
  projects.push("guides");
5426
6286
  }
5427
- if (blueprint.skills) {
6287
+ if (planned.has("skills")) {
5428
6288
  factories.push(CONFIG_TEMPLATES.factories.skills);
5429
6289
  projects.push("skills");
5430
6290
  }
5431
- if (blueprint.conformance) {
6291
+ if (planned.has("conformance")) {
5432
6292
  factories.push(CONFIG_TEMPLATES.factories.conformance);
5433
6293
  projects.push("conformance");
5434
6294
  }
5435
- if (blueprint.service) {
6295
+ if (planned.has("service")) {
5436
6296
  factories.push(CONFIG_TEMPLATES.factories.service);
5437
6297
  projects.push("service");
5438
6298
  }
5439
- if (publishes) {
6299
+ if (planned.has("distribution")) {
5440
6300
  factories.push(CONFIG_TEMPLATES.factories.distribution);
5441
6301
  projects.push("distribution");
5442
6302
  }
5443
- if (blueprint.integration) {
5444
- factories.push(fillTemplate(CONFIG_TEMPLATES.factories.integration, { global }));
6303
+ if (planned.has("integration")) {
6304
+ factories.push(fillTemplate(styled ? CONFIG_TEMPLATES.factories.integration.sheet : CONFIG_TEMPLATES.factories.integration.module, { global }));
5445
6305
  projects.push("integration");
5446
6306
  }
5447
6307
  factories.push(CONFIG_TEMPLATES.factories.probe);
@@ -5454,14 +6314,24 @@ ${projects.map((project) => `\t\t\t${project},`).join("\n")}
5454
6314
  const helpers = [
5455
6315
  "enforceBuildLog",
5456
6316
  "environmentBoundary",
5457
- "outputBoundary"
6317
+ "outputBoundary",
6318
+ "resolveApplication",
6319
+ "resolveExternal",
6320
+ "stampPage"
5458
6321
  ].filter((helper) => body.includes(helper));
6322
+ const helperImport = `import { ${helpers.join(", ")} } from './configs/helpers.js'\n`;
5459
6323
  return fillTemplate(CONFIG_TEMPLATES.root.vite, {
5460
- journey: blueprint.journey && machinery.vue ? "import type { JourneyVariant } from '@orkestrel/test'\n" : "",
6324
+ journey: blueprint.journey && blueprint.app.includes("browser") ? "import type { JourneyVariant } from '@orkestrel/test'\n" : "",
5461
6325
  imports: imports.length === 0 ? "" : `${imports.join("\n")}\n`,
5462
- helpers: helpers.length === 0 ? "" : `import { ${helpers.join(", ")} } from './configs/helpers.js'\n`,
6326
+ helpers: helpers.length === 0 ? "" : matchesPrintWidth(helperImport.trimEnd()) ? helperImport : `import {\n${helpers.map((helper) => `\t${helper},`).join("\n")}\n} from './configs/helpers.js'\n`,
5463
6327
  browsers: machinery.browser ? "import { resolveBrowser, resolvePinnedBrowser } from './configs/browsers.js'\n" : "",
5464
- options: (machinery.browser ? "const browserOptions = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)\n\n" : "") + (blueprint.journey && machinery.vue ? "const capture = process.env.CAPTURE === '1'\n\n" : ""),
6328
+ options: (machinery.browser ? `const browserOptions = resolveBrowser(resolvePinnedBrowser(), process.platform, process.env)
6329
+
6330
+ const optimizeDeps = {\n\tinclude: ${JSON.stringify([
6331
+ "@orkestrel/test",
6332
+ "@orkestrel/test/browser",
6333
+ ...Object.hasOwn(blueprintToDevDependencies(blueprint), "@orkestrel/contract") || blueprint.dependencies.some((dependency) => dependency.name === "@orkestrel/contract") || blueprint.peers.some((peer) => peer.name === "@orkestrel/contract") ? ["@orkestrel/contract"] : []
6334
+ ]).replaceAll("\"", "'").replaceAll(",", ", ")},\n}\n\n` : "") + (blueprint.journey && blueprint.app.includes("browser") ? "const capture = process.env.CAPTURE === '1'\n\n" : "") + ((blueprint.journey || blueprint.showcase) && blueprint.app.includes("browser") ? `const applications = {\n\tbrowser: appBrowser,\n${blueprintToFaces(blueprint).filter((extension) => extension.surface === "browser" && extension.axes.includes("app")).map((extension) => `\t${extension.name}: app${extension.name[0]?.toUpperCase()}${extension.name.slice(1)},\n`).join("")}}\n\n` : ""),
5465
6335
  factories: body,
5466
6336
  projects: projectRows
5467
6337
  });
@@ -5502,6 +6372,26 @@ function blueprintToConfigArtifacts(blueprint) {
5502
6372
  origin: "template",
5503
6373
  content: CONFIG_TEMPLATES.browsers
5504
6374
  });
6375
+ for (const name of [...blueprintToSheets(blueprint), ...blueprint.themes ? ["styles/themes"] : []]) {
6376
+ const label = name === "styles/themes" ? "themes" : name;
6377
+ artifacts.push({
6378
+ path: `configs/src/vite.${label}.config.ts`,
6379
+ group: "configs",
6380
+ ownership: "content",
6381
+ origin: "template",
6382
+ content: fillTemplate(CONFIG_TEMPLATES.vites.sheet, {
6383
+ name,
6384
+ label
6385
+ })
6386
+ });
6387
+ if (name !== "styles/themes") artifacts.push({
6388
+ path: `configs/src/tsconfig.${name}.json`,
6389
+ group: "configs",
6390
+ ownership: "content",
6391
+ origin: "template",
6392
+ content: fillTemplate(CONFIG_TEMPLATES.tsconfigs.sheet, { name })
6393
+ });
6394
+ }
5505
6395
  for (const environment of blueprint.src) for (const path of SRC_MATRIX[environment].configs) {
5506
6396
  let content = CONFIG_TEMPLATES.vites.src.core;
5507
6397
  if (path === "configs/src/tsconfig.core.json") content = CONFIG_TEMPLATES.tsconfigs.src.core;
@@ -5539,11 +6429,10 @@ ${paths.join("\n")}
5539
6429
  "../../app/browser/**/*.cts",
5540
6430
  "../../app/browser/**/*.mts",
5541
6431
  "../../app/browser/**/*.ts",
5542
- "../../app/browser/**/*.tsx",
5543
- "../../app/browser/**/*.vue"
6432
+ "../../app/browser/**/*.tsx"
5544
6433
  ];
5545
6434
  if (blueprint.app.includes("core")) include.push("../../app/core/**/*.cts", "../../app/core/**/*.mts", "../../app/core/**/*.ts", "../../app/core/**/*.tsx");
5546
- include.push("../../tests/app/browser/**/*.cts", "../../tests/app/browser/**/*.mts", "../../tests/app/browser/**/*.ts", "../../tests/app/browser/**/*.tsx", "../../tests/app/browser/**/*.vue", "../../tests/setup.ts", "../../tests/setupBrowser.ts");
6435
+ include.push("../../tests/app/browser/**/*.cts", "../../tests/app/browser/**/*.mts", "../../tests/app/browser/**/*.ts", "../../tests/app/browser/**/*.tsx", "../../tests/setup.ts", "../../tests/setupBrowser.ts");
5547
6436
  content = fillTemplate(CONFIG_TEMPLATES.tsconfigs.app.browser, { include: include.map((entry, index) => `\t\t${JSON.stringify(entry)}${index === include.length - 1 ? "" : ","}`).join("\n") });
5548
6437
  } else if (path === "configs/app/vite.server.config.ts") content = CONFIG_TEMPLATES.vites.app.server;
5549
6438
  else if (path === "configs/app/tsconfig.server.json") {
@@ -5566,6 +6455,58 @@ ${paths.join("\n")}
5566
6455
  content
5567
6456
  });
5568
6457
  }
6458
+ for (const extension of blueprintToFaces(blueprint)) {
6459
+ if (extension.surface !== "browser") continue;
6460
+ for (const axis of extension.axes) {
6461
+ const include = [
6462
+ ...[
6463
+ "cts",
6464
+ "mts",
6465
+ "ts",
6466
+ "tsx",
6467
+ ...FRAMEWORK_MATRIX[extension.name].suffixes
6468
+ ].map((suffix) => `../../app/${extension.name}/**/*.${suffix}`),
6469
+ ...blueprint.app.includes("core") ? [
6470
+ "cts",
6471
+ "mts",
6472
+ "ts",
6473
+ "tsx"
6474
+ ].map((suffix) => `../../app/core/**/*.${suffix}`) : [],
6475
+ ...[
6476
+ "cts",
6477
+ "mts",
6478
+ "ts",
6479
+ "tsx",
6480
+ ...FRAMEWORK_MATRIX[extension.name].suffixes
6481
+ ].map((suffix) => `../../tests/app/${extension.name}/**/*.${suffix}`),
6482
+ "../../tests/setup.ts",
6483
+ "../../tests/setupBrowser.ts"
6484
+ ];
6485
+ const siblings = blueprint.src.filter((environment) => environment === "core" || environment === "browser").flatMap((environment) => ["ts", "js"].map((suffix) => {
6486
+ const key = `\t[resolveWorkspacePath('src/${environment}/index.${suffix}').replaceAll('\\\\', '/')]:`;
6487
+ const value = `'@orkestrel/${blueprint.name}${environment === "browser" ? "/browser" : ""}',`;
6488
+ return matchesPrintWidth(`${key} ${value}`) ? `${key} ${value}` : `${key}\n\t\t${value}`;
6489
+ })).join("\n");
6490
+ artifacts.push({
6491
+ path: `configs/${axis}/vite.${extension.name}.config.ts`,
6492
+ group: "configs",
6493
+ ownership: "content",
6494
+ origin: "template",
6495
+ environment: "browser",
6496
+ content: axis === "src" ? fillTemplate(CONFIG_TEMPLATES.vites.src.vue, {
6497
+ siblings,
6498
+ refused: `[${FRAMEWORK_MATRIX[extension.name].refused.map((name) => serializeTypeScriptString(name)).join(", ")}]`
6499
+ }) : CONFIG_TEMPLATES.vites.app.vue
6500
+ }, {
6501
+ path: `configs/${axis}/tsconfig.${extension.name}.json`,
6502
+ group: "configs",
6503
+ ownership: "content",
6504
+ origin: "template",
6505
+ environment: "browser",
6506
+ content: axis === "src" ? CONFIG_TEMPLATES.tsconfigs.vue.src : fillTemplate(CONFIG_TEMPLATES.tsconfigs.vue.app, { include: include.map((entry, index) => `\t\t${JSON.stringify(entry)}${index === include.length - 1 ? "" : ","}`).join("\n") })
6507
+ });
6508
+ }
6509
+ }
5569
6510
  if (blueprint.showcase && blueprint.app.includes("browser")) artifacts.push({
5570
6511
  path: SHOWCASE_CONFIG_PATH,
5571
6512
  group: "configs",
@@ -5595,15 +6536,11 @@ ${paths.join("\n")}
5595
6536
  * Compiles every artifact in the `source` group.
5596
6537
  *
5597
6538
  * @param blueprint - The workspace specification.
5598
- * @returns Empty published barrels, selected application entries, and the optional bin entry.
6539
+ * @returns Published barrels, sheet seeds, selected application entries, and the optional bin entry.
5599
6540
  *
5600
6541
  * @remarks
5601
- * The barrels and every runtime entry intentionally hold nothing. A generated
5602
- * sample entity would read as package implementation, so the
5603
- * scaffold establishes only the selected environment boundaries. An application
5604
- * entry is empty for the same reason the bin entry is, and because the vendored
5605
- * lint config refuses an unassigned import outside a stylesheet, so the entry
5606
- * cannot start by importing its barrel for effect either.
6542
+ * Barrels, server entries, and bin entries hold no starter implementation. Browser entries
6543
+ * render the workspace name as a level-one heading; the Vue face mounts its arrival component.
5607
6544
  *
5608
6545
  * @example
5609
6546
  * ```ts
@@ -5616,6 +6553,20 @@ ${paths.join("\n")}
5616
6553
  */
5617
6554
  function blueprintToSourceArtifacts(blueprint) {
5618
6555
  const artifacts = [];
6556
+ if (blueprint.themes && !blueprint.styles) artifacts.push({
6557
+ path: "src/styles/_tokens.scss",
6558
+ group: "source",
6559
+ ownership: "birth",
6560
+ origin: "template",
6561
+ content: ARTIFACT_TEMPLATES.source.sheet["_tokens.scss"]
6562
+ });
6563
+ for (const name of [...blueprintToSheets(blueprint), ...blueprint.themes ? ["styles/themes"] : []]) for (const [path, content] of Object.entries(name === "styles/themes" ? ARTIFACT_TEMPLATES.source.themes : ARTIFACT_TEMPLATES.source.sheet)) artifacts.push({
6564
+ path: `src/${name}/${path}`,
6565
+ group: "source",
6566
+ ownership: "birth",
6567
+ origin: "template",
6568
+ content
6569
+ });
5619
6570
  for (const environment of blueprint.src) artifacts.push({
5620
6571
  path: `src/${environment}/index.ts`,
5621
6572
  group: "source",
@@ -5639,7 +6590,7 @@ function blueprintToSourceArtifacts(blueprint) {
5639
6590
  ownership: "birth",
5640
6591
  origin: "template",
5641
6592
  environment,
5642
- content: ARTIFACT_TEMPLATES.source.empty
6593
+ content: fillTemplate(ARTIFACT_TEMPLATES.source.main, { heading: `${matchesPrintWidth(`\t.appendChild(document.createElement('h1')).textContent = ${serializeTypeScriptString(blueprint.name)}`) ? " " : "\n "}${serializeTypeScriptString(blueprint.name)}` })
5643
6594
  }, {
5644
6595
  path: "app/browser/index.html",
5645
6596
  group: "source",
@@ -5657,6 +6608,36 @@ function blueprintToSourceArtifacts(blueprint) {
5657
6608
  content: ARTIFACT_TEMPLATES.source.empty
5658
6609
  });
5659
6610
  }
6611
+ for (const extension of blueprintToFaces(blueprint)) {
6612
+ if (extension.surface !== "browser") continue;
6613
+ for (const axis of extension.axes) {
6614
+ artifacts.push({
6615
+ path: `${axis}/${extension.name}/index.ts`,
6616
+ group: "source",
6617
+ ownership: "birth",
6618
+ origin: "template",
6619
+ environment: "browser",
6620
+ content: axis === "app" ? ARTIFACT_TEMPLATES.source.empty : ARTIFACT_TEMPLATES.source.barrel
6621
+ });
6622
+ if (axis !== "app") continue;
6623
+ artifacts.push({
6624
+ path: `app/${extension.name}/index.html`,
6625
+ group: "source",
6626
+ ownership: "birth",
6627
+ origin: "template",
6628
+ environment: "browser",
6629
+ content: ARTIFACT_TEMPLATES.source.browser
6630
+ });
6631
+ for (const [path, content] of Object.entries(ARTIFACT_TEMPLATES.source.vue)) artifacts.push({
6632
+ path: `app/${extension.name}/${path}`,
6633
+ group: "source",
6634
+ ownership: "birth",
6635
+ origin: "template",
6636
+ environment: "browser",
6637
+ content: fillTemplate(content, { heading: matchesPrintWidth(`\t<h1>${blueprint.name}</h1>`) ? blueprint.name : `\n\t\t${blueprint.name}\n\t` })
6638
+ });
6639
+ }
6640
+ }
5660
6641
  if (blueprint.bin) artifacts.push({
5661
6642
  path: BIN_ENTRY_PATH,
5662
6643
  group: "source",
@@ -5670,7 +6651,7 @@ function blueprintToSourceArtifacts(blueprint) {
5670
6651
  * Compiles every artifact in the `tests` group that is not vendored from the host.
5671
6652
  *
5672
6653
  * @param blueprint - The workspace specification.
5673
- * @returns Shared setup modules, axis tests, and the optional integration seed.
6654
+ * @returns Shared setup modules and proofs, axis and sheet tests, journey suites, and the optional integration seed.
5674
6655
  *
5675
6656
  * @remarks
5676
6657
  * `tests/setupPolicy.ts`, `tests/policy.test.ts`, and `tests/config.test.ts` are
@@ -5709,15 +6690,53 @@ function blueprintToTestArtifacts(blueprint) {
5709
6690
  origin: "template",
5710
6691
  content: ARTIFACT_TEMPLATES.tests.setup
5711
6692
  }];
6693
+ const sheets = [...blueprintToSheets(blueprint), ...blueprint.themes ? ["styles/themes"] : []];
6694
+ for (const extension of blueprintToFaces(blueprint)) {
6695
+ if (extension.surface !== "browser") continue;
6696
+ for (const axis of extension.axes) artifacts.push({
6697
+ path: `tests/${axis}/${extension.name}/index.test.ts`,
6698
+ group: "tests",
6699
+ ownership: "birth",
6700
+ origin: "template",
6701
+ environment: "browser",
6702
+ content: fillTemplate(ARTIFACT_TEMPLATES.tests.entry, {
6703
+ specifier: serializeTypeScriptString(`@${axis}/${extension.name}`),
6704
+ label: serializeTypeScriptString(`${axis} ${extension.name} entry`)
6705
+ })
6706
+ });
6707
+ }
6708
+ if (sheets.length > 0) artifacts.push({
6709
+ path: "tests/setupStyles.ts",
6710
+ group: "tests",
6711
+ ownership: "birth",
6712
+ origin: "template",
6713
+ content: ARTIFACT_TEMPLATES.tests.styles.module
6714
+ }, {
6715
+ path: "tests/setupStyles.test.ts",
6716
+ group: "tests",
6717
+ ownership: "birth",
6718
+ origin: "template",
6719
+ content: ARTIFACT_TEMPLATES.tests.styles.proof
6720
+ });
6721
+ for (const name of sheets) artifacts.push({
6722
+ path: `tests/src/${name}/index.test.ts`,
6723
+ group: "tests",
6724
+ ownership: "birth",
6725
+ origin: "template",
6726
+ content: fillTemplate(ARTIFACT_TEMPLATES.tests.sheet, {
6727
+ name,
6728
+ setup: name === "styles/themes" ? "../../../setupStyles.js" : "../../setupStyles.js"
6729
+ })
6730
+ });
5712
6731
  if (blueprintToMachinery(blueprint).browser) artifacts.push({
5713
6732
  path: "tests/setupBrowser.ts",
5714
6733
  group: "tests",
5715
6734
  ownership: "birth",
5716
6735
  origin: "template",
5717
6736
  environment: "browser",
5718
- content: ARTIFACT_TEMPLATES.tests.setup
6737
+ content: blueprint.journey ? ARTIFACT_TEMPLATES.tests.browser : ARTIFACT_TEMPLATES.tests.setup
5719
6738
  });
5720
- if (blueprint.src.includes("server") || blueprint.app.includes("server") || blueprint.bin) artifacts.push({
6739
+ if (blueprint.src.includes("server") || blueprint.app.includes("server") || blueprint.bin || blueprint.conformance) artifacts.push({
5721
6740
  path: "tests/setupServer.ts",
5722
6741
  group: "tests",
5723
6742
  ownership: "birth",
@@ -5732,13 +6751,40 @@ function blueprintToTestArtifacts(blueprint) {
5732
6751
  origin: "template",
5733
6752
  content: ARTIFACT_TEMPLATES.tests.setup
5734
6753
  });
5735
- if (blueprint.global) artifacts.push({
5736
- path: GLOBAL_SETUP_PATH,
5737
- group: "tests",
5738
- ownership: "birth",
5739
- origin: "template",
5740
- content: ARTIFACT_TEMPLATES.tests.global
5741
- });
6754
+ if (blueprint.global) {
6755
+ artifacts.push({
6756
+ path: GLOBAL_SETUP_PATH,
6757
+ group: "tests",
6758
+ ownership: "birth",
6759
+ origin: "template",
6760
+ content: ARTIFACT_TEMPLATES.tests.global.module
6761
+ });
6762
+ artifacts.push({
6763
+ path: "tests/setupGlobal.test.ts",
6764
+ group: "tests",
6765
+ ownership: "birth",
6766
+ origin: "template",
6767
+ content: ARTIFACT_TEMPLATES.tests.global.proof
6768
+ });
6769
+ }
6770
+ if (blueprint.journey && blueprint.app.includes("browser")) {
6771
+ const applications = ["browser", ...blueprintToFaces(blueprint).flatMap((extension) => extension.surface === "browser" && extension.axes.includes("app") ? [extension.name] : [])];
6772
+ for (const application of applications) artifacts.push({
6773
+ path: `tests/app/${application}/integration.test.ts`,
6774
+ group: "tests",
6775
+ ownership: "birth",
6776
+ origin: "template",
6777
+ environment: "browser",
6778
+ content: fillTemplate(ARTIFACT_TEMPLATES.tests.journey, {
6779
+ application,
6780
+ heading: serializeTypeScriptString(blueprint.name),
6781
+ imports: application === "vue" ? "import { createApp } from 'vue'\nimport App from '../../../app/vue/App.vue'\n" : "",
6782
+ mount: application === "vue" ? " const container = document.body.appendChild(document.createElement('main'))\n const app = createApp(App)\n" : "",
6783
+ arrival: application === "vue" ? " app.mount(container)\n" : " await import('../../../app/browser/main.js')\n",
6784
+ cleanup: application === "vue" ? " app.unmount()\n container.remove()\n" : " for (const main of page.getByRole('main').elements()) main.remove()\n"
6785
+ })
6786
+ });
6787
+ }
5742
6788
  for (const environment of blueprint.src) artifacts.push({
5743
6789
  path: `tests/src/${environment}/index.test.ts`,
5744
6790
  group: "tests",
@@ -5773,7 +6819,7 @@ function blueprintToTestArtifacts(blueprint) {
5773
6819
  label: serializeTypeScriptString(`app ${environment} entry`)
5774
6820
  })
5775
6821
  });
5776
- if (blueprint.src.length > 0) {
6822
+ if (blueprint.src.length > 0 || blueprintToSheets(blueprint).length > 0 || blueprint.themes) {
5777
6823
  const browser = blueprint.src.includes("browser");
5778
6824
  const distribution = ARTIFACT_TEMPLATES.tests.distribution;
5779
6825
  artifacts.push({
@@ -5842,7 +6888,12 @@ function blueprintToGuideArtifacts(blueprint) {
5842
6888
  const tests = [];
5843
6889
  const directories = [];
5844
6890
  const guide = `guides/${blueprint.name}.md`;
5845
- for (const environment of blueprint.src) {
6891
+ for (const environment of [
6892
+ ...blueprint.src,
6893
+ ...blueprintToFaces(blueprint).filter((extension) => extension.axes.includes("src")).map((extension) => extension.name),
6894
+ ...blueprintToSheets(blueprint),
6895
+ ...blueprint.themes ? ["styles/themes"] : []
6896
+ ]) {
5846
6897
  source.push(` - [\`src/${environment}\`](../src/${environment})`);
5847
6898
  tests.push(` - [\`tests/src/${environment}\`](../tests/src/${environment})`);
5848
6899
  directories.push(`- [\`src/${environment}\`](../src/${environment})\n - Guide: Not created. Create this file when the workspace has a public surface:\n \`${guide}\`\n - Tests: [\`tests/src/${environment}\`](../tests/src/${environment})`);
@@ -5852,7 +6903,7 @@ function blueprintToGuideArtifacts(blueprint) {
5852
6903
  tests.push(" - [`tests/src/bin`](../tests/src/bin)");
5853
6904
  directories.push(`- [\`src/bin\`](../src/bin)\n - Guide: Not created. Create this file when the workspace has a public surface:\n \`${guide}\`\n - Tests: [\`tests/src/bin\`](../tests/src/bin)`);
5854
6905
  }
5855
- for (const environment of blueprint.app) {
6906
+ for (const environment of [...blueprint.app, ...blueprintToFaces(blueprint).filter((extension) => extension.axes.includes("app")).map((extension) => extension.name)]) {
5856
6907
  source.push(` - [\`app/${environment}\`](../app/${environment})`);
5857
6908
  tests.push(` - [\`tests/app/${environment}\`](../tests/app/${environment})`);
5858
6909
  directories.push(`- [\`app/${environment}\`](../app/${environment})\n - Guide: Not created. Create this file when the workspace has a public surface:\n \`${guide}\`\n - Tests: [\`tests/app/${environment}\`](../tests/app/${environment})`);
@@ -5864,7 +6915,7 @@ function blueprintToGuideArtifacts(blueprint) {
5864
6915
  origin: "template",
5865
6916
  content: fillTemplate(ARTIFACT_TEMPLATES.guides.readme, {
5866
6917
  source: source.join("\n"),
5867
- tests: tests.join("\n"),
6918
+ tests: tests.join("\n") + (blueprint.showcase && blueprint.app.includes("browser") ? "\n - Showcase:\n" + ["browser", ...blueprintToFaces(blueprint).filter((extension) => extension.axes.includes("app")).map((extension) => extension.name)].map((application) => ` - [\`showcase/${application}.html\`](../showcase/${application}.html)`).join("\n") : ""),
5868
6919
  directories: directories.join("\n"),
5869
6920
  guide: blueprint.name
5870
6921
  })
@@ -5903,7 +6954,7 @@ function blueprintToGuideArtifacts(blueprint) {
5903
6954
  * ```
5904
6955
  */
5905
6956
  function blueprintToDocumentArtifacts(blueprint) {
5906
- const publishes = blueprint.src.length > 0;
6957
+ const publishes = blueprint.src.length > 0 || blueprintToSheets(blueprint).length > 0 || blueprint.themes;
5907
6958
  const name = publishes ? `@orkestrel/${blueprint.name}` : blueprint.name;
5908
6959
  const description = blueprint.description ?? (publishes ? `The ${name} package.` : `The ${name} application.`);
5909
6960
  return [{
@@ -6695,7 +7746,8 @@ function dependenciesToQuestions(dependencies, field, name, range) {
6695
7746
  * These do not, because each describes a workspace it can describe honestly but
6696
7747
  * will not create: a published axis of several environments without core,
6697
7748
  * whose manifest names a core build the workspace never runs; a showcase flag
6698
- * whose required browser axis is absent, which emits nothing; and an
7749
+ * or journey flag whose required browser axis is absent, which emits nothing; an unplaced browser
7750
+ * extension or a styles extension without the styles surface; and an
6699
7751
  * integration flag over fewer than two environments, whose seed does emit and
6700
7752
  * has nothing to compose across. Blocking any of them closed the gate for every
6701
7753
  * verb. The verbs that read an existing workspace need the plan the gate
@@ -6736,7 +7788,7 @@ function blueprintToQuestions(blueprint) {
6736
7788
  message: `${blueprint.engines} is not a supported minimum-Node floor.`,
6737
7789
  blocking: true
6738
7790
  });
6739
- if (blueprint.src.length === 0 && blueprint.app.length === 0) questions.push({
7791
+ if (blueprint.src.length === 0 && blueprint.app.length === 0 && blueprintToSheets(blueprint).length === 0 && !blueprint.themes) questions.push({
6740
7792
  field: "src",
6741
7793
  message: "A workspace declares at least one environment on src or app.",
6742
7794
  blocking: true,
@@ -6762,6 +7814,32 @@ function blueprintToQuestions(blueprint) {
6762
7814
  candidates: ENVIRONMENTS
6763
7815
  });
6764
7816
  }
7817
+ const extensions = /* @__PURE__ */ new Set();
7818
+ for (const extension of blueprint.extensions) {
7819
+ const selection = `${extension.surface}:${extension.name}`;
7820
+ if (extensions.has(selection)) questions.push({
7821
+ field: "extensions",
7822
+ message: `${selection} is declared more than once on extensions.`,
7823
+ blocking: true
7824
+ });
7825
+ extensions.add(selection);
7826
+ if (extension.surface === "browser") {
7827
+ if (extension.axes.length === 0) questions.push({
7828
+ field: "extensions",
7829
+ message: `${selection} occupies no axis.`,
7830
+ blocking: false
7831
+ });
7832
+ for (const axis of extension.axes) if (!blueprint[axis].includes("browser")) questions.push({
7833
+ field: "extensions",
7834
+ message: `${selection} occupies ${axis}, whose selection lacks browser.`,
7835
+ blocking: false
7836
+ });
7837
+ } else if (!blueprint.styles) questions.push({
7838
+ field: "extensions",
7839
+ message: `${selection} extends a styles surface this workspace does not declare.`,
7840
+ blocking: false
7841
+ });
7842
+ }
6765
7843
  if (blueprint.integration && blueprint.src.length + blueprint.app.length < 2) questions.push({
6766
7844
  field: "integration",
6767
7845
  message: "integration drives features across environments, and this workspace declares fewer than two, so its seed composes nothing.",
@@ -6991,6 +8069,9 @@ function createBlueprint(name, input) {
6991
8069
  keywords: input?.keywords ?? [],
6992
8070
  src: input?.src ?? [],
6993
8071
  app: input?.app ?? [],
8072
+ extensions: input?.extensions ?? [],
8073
+ styles: input?.styles ?? false,
8074
+ themes: input?.themes ?? false,
6994
8075
  dependencies: input?.dependencies ?? [],
6995
8076
  peers: input?.peers ?? [],
6996
8077
  extras: input?.extras ?? [],
@@ -7316,6 +8397,6 @@ var Compiler = class {
7316
8397
  }
7317
8398
  };
7318
8399
  //#endregion
7319
- 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, JOURNEY_CONFIG_PATH, 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, REFERENCE_PATHS, RELEASE_PROOF_COMMAND, SEED_GUIDE_PATHS, SERVICE_SCRIPT_PATH, SERVICE_SETUP_PATH, SERVICE_TEST_INCLUDE, SHOWCASE_CONFIG_PATH, SHOWCASE_DEV_DEPENDENCIES, SKILLS_CONFIG_PATH, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, ScaffoldError, TAB_WIDTH, TARGET_SKILL_NAMES, 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, renderSkillPointer, replaceManifestRanges, replaceManifestScripts, replacePlanRanges, selectGroups, selectHostPaths, serializeTypeScriptString, srcToEntry, srcToExports, srcToRoot };
8400
+ export { APP_BROWSER_DEV_DEPENDENCIES, APP_DEV_DEPENDENCIES, APP_MATRIX, APP_SERVER_DEV_DEPENDENCIES, ARTIFACT_TEMPLATES, AXES, 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, FRAMEWORKS, FRAMEWORK_MATRIX, GLOBAL_SETUP_PATH, GROUPS, GUIDES_TEST_PATH, HEX_PATTERN, HOST_INVENTORY_PATH, HOST_PATHS, INTEGRATION_TEST_PATH, INVALID_PATH_CHARACTER_PATTERN, JOURNEY_CONFIG_PATH, 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, REFERENCE_PATHS, RELEASE_PROOF_COMMAND, RESERVED_SHEET_NAMES, SEED_GUIDE_PATHS, SERVICE_SCRIPT_PATH, SERVICE_SETUP_PATH, SERVICE_TEST_INCLUDE, SHEET_ENTRY_NAME, SHOWCASE_CONFIG_PATH, SHOWCASE_DEV_DEPENDENCIES, SHOWCASE_PAGES_PATH, SKILLS_CONFIG_PATH, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, STYLES_DEV_DEPENDENCIES, STYLES_ENTRY_PATH, SURFACES, ScaffoldError, TAB_WIDTH, TARGET_SKILL_NAMES, THEMES_BARREL_PATH, THEMES_ENTRY_PATH, VERSION_PATTERN, WORKSPACE_DEV_ENGINES, WORKSPACE_OWNED_PATHS, applyOverrides, artifactToFinding, artifactToHex, artifactsToQuestions, blueprintToConfigArtifacts, blueprintToDevDependencies, blueprintToDocumentArtifacts, blueprintToExports, blueprintToFaces, blueprintToGuideArtifacts, blueprintToHostArtifacts, blueprintToMachinery, blueprintToManifest, blueprintToOrchestrationArtifacts, blueprintToProjects, blueprintToQuestions, blueprintToRootTsconfig, blueprintToRootVite, blueprintToScripts, blueprintToSheets, blueprintToSourceArtifacts, blueprintToTestArtifacts, blueprintToWritableScripts, bytesToHex, catalogToLayers, cloneValue, compareVersions, computeBytes, computeHash, contentToHex, createBlueprint, dependenciesToQuestions, extractRangeMajor, extractVersion, inferDrift, inferGroup, isArtifact, isAudit, isBlueprint, isBrowserExtension, isCanonPath, isCatalogEntry, isCollection, isCompilerHooks, isCompilerOptions, isContent, isDeferredPath, isDependency, isDependencyName, isEnvironment, isExtension, isFinding, isFloorPath, isGroup, isGroups, isHex, isManifestScript, isMirror, isOverride, isPath, isPlan, isQuestion, isRetainedPath, isScaffoldError, isSheetName, isSnapshot, isStylesExtension, isSurface, manifestToDependencies, manifestToName, matchesDriftReachability, matchesEngines, matchesOrchestrationPath, matchesPrintWidth, matchesRange, nameToGuide, overridesToQuestions, parseBlueprint, parseCompilerOptions, parseExtension, parseGroups, parseSnapshot, pathToCondition, planToFindings, planToHash, planToSummary, renderSkillPointer, replaceManifestRanges, replaceManifestScripts, replacePlanRanges, selectGroups, selectHostPaths, serializeTypeScriptString, srcToEntry, srcToExports, srcToRoot };
7320
8401
 
7321
8402
  //# sourceMappingURL=index.js.map