@orkestrel/scaffold 0.0.5 → 0.0.7

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.
@@ -103,9 +103,12 @@ var APP_MATRIX = Object.freeze({
103
103
  * The root docs (`AGENTS.md` / `CLAUDE.md`), `LICENSE`, `.agents`, `.claude`, `.codex`,
104
104
  * the four SessionStart hook scripts (`scripts/deps.sh` / `scripts/cursor.sh` /
105
105
  * `scripts/codex.sh` / `scripts/ollama.sh`), the repository coding-law policy module,
106
- * the line's seven byte-identical root dotfiles, and the two guides-grouped mirrors every repo carries: the line-wide
107
- * dev-tooling guide (`guides/src/guide.md`) and the
108
- * scaffold engine's own self-guide (`guides/src/scaffold.md`).
106
+ * the line's seven byte-identical root dotfiles, and the two guides-grouped
107
+ * mirror candidates: the line-wide dev-tooling guide
108
+ * (`guides/src/guide.md`) and the scaffold engine's own self-guide
109
+ * (`guides/src/scaffold.md`). `stageHost` vendors both; each plan carries the
110
+ * subset selected by `selectHostPaths`, omitting the target blueprint's own
111
+ * guide.
109
112
  */
110
113
  var HOST_PATHS = Object.freeze([
111
114
  "AGENTS.md",
@@ -217,15 +220,15 @@ var DEFAULT_VERSION = "0.0.1";
217
220
  /** The `engines.node` range the `blueprint` builder fills. */
218
221
  var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
219
222
  /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
220
- var SCAFFOLD_RANGE = "^0.0.5";
223
+ var SCAFFOLD_RANGE = "^0.0.7";
221
224
  /** Tooling versions shared by scaffold and every generated workspace. */
222
225
  var BASE_DEV_DEPENDENCIES = Object.freeze({
223
226
  "@microsoft/api-extractor": "^7.58.12",
224
227
  "@orkestrel/guide": "^0.0.5",
225
228
  "@orkestrel/scaffold": SCAFFOLD_RANGE,
226
- "@types/node": "^26.1.1",
227
- oxfmt: "^0.60.0",
228
- oxlint: "^1.75.0",
229
+ "@types/node": "^26.1.2",
230
+ oxfmt: "^0.61.0",
231
+ oxlint: "^1.76.0",
229
232
  typescript: "^6.0.3",
230
233
  vite: "^8.1.5",
231
234
  "vite-plugin-dts": "^5.0.3",
@@ -1139,6 +1142,22 @@ function snapshotOf(current) {
1139
1142
  return Object.fromEntries(entries);
1140
1143
  }
1141
1144
  /**
1145
+ * Select host paths without the guide owned by the target blueprint.
1146
+ *
1147
+ * @param paths - Host artifact paths in deterministic input order.
1148
+ * @param name - The target blueprint's unscoped package name.
1149
+ * @returns Every host path except `guides/src/<name>.md`, in input order.
1150
+ *
1151
+ * @example
1152
+ * ```ts
1153
+ * selectHostPaths(['guides/src/guide.md', 'LICENSE'], 'guide') // ['LICENSE']
1154
+ * ```
1155
+ */
1156
+ function selectHostPaths(paths, name) {
1157
+ const guide = `guides/src/${name}.md`;
1158
+ return paths.filter((path) => path !== guide);
1159
+ }
1160
+ /**
1142
1161
  * Find the first exact or portable case-insensitive path collision.
1143
1162
  *
1144
1163
  * @param paths - Portable paths in deterministic input order.
@@ -1441,6 +1460,29 @@ function manifestToDependencies(manifestText) {
1441
1460
  return dependencies;
1442
1461
  }
1443
1462
  /**
1463
+ * Project a `package.json` text to its own string `name`.
1464
+ *
1465
+ * @param manifest - The `package.json` file content.
1466
+ * @returns The own string `name`, or `undefined` when the manifest exceeds its
1467
+ * byte ceiling, is malformed, has a non-object root, or has no own string
1468
+ * `name`.
1469
+ *
1470
+ * @example
1471
+ * ```ts
1472
+ * import { manifestToName } from '@orkestrel/scaffold'
1473
+ *
1474
+ * manifestToName('{"name":"@orkestrel/router"}') // '@orkestrel/router'
1475
+ * manifestToName('{}') // undefined
1476
+ * ```
1477
+ */
1478
+ function manifestToName(manifest) {
1479
+ if (manifest.length > 1048576 || contentByteLength(manifest) > 1048576) return;
1480
+ const parsed = parseJSON(manifest);
1481
+ if (!isRecord(parsed)) return void 0;
1482
+ const name = ownDataValue(parsed, "name");
1483
+ return typeof name === "string" ? name : void 0;
1484
+ }
1485
+ /**
1444
1486
  * Compare a declared range to the registry latest.
1445
1487
  *
1446
1488
  * @param range - The declared semver range.
@@ -2145,6 +2187,7 @@ var isPlan = andOf(andOf(createContract(planShape()).is, hasValidPlanHex), hasVa
2145
2187
  function validatePlan(plan) {
2146
2188
  const blueprintValidation = validateBlueprint(plan.blueprint);
2147
2189
  const questions = [...blueprintValidation.questions];
2190
+ const warnings = [...blueprintValidation.warnings];
2148
2191
  if (!hasValidPlanBytes(plan)) questions.push({
2149
2192
  field: "artifacts",
2150
2193
  text: "Plan artifact content exceeds the retained byte limits",
@@ -2169,16 +2212,20 @@ function validatePlan(plan) {
2169
2212
  });
2170
2213
  continue;
2171
2214
  }
2172
- if (artifact.path === "package.json") questions.push({
2173
- field: "overrides",
2174
- text: "Override path \"package.json\" targets the blueprint-owned publication boundary",
2175
- blocking: true
2176
- });
2215
+ if (artifact.path === "package.json") {
2216
+ questions.push({
2217
+ field: "overrides",
2218
+ text: "Override path \"package.json\" targets the blueprint-owned publication boundary",
2219
+ blocking: true
2220
+ });
2221
+ continue;
2222
+ }
2223
+ warnings.push(`Override path "${item.path}" replaces its planned artifact content`);
2177
2224
  }
2178
2225
  return {
2179
2226
  valid: questions.length === 0,
2180
2227
  questions,
2181
- warnings: blueprintValidation.warnings
2228
+ warnings
2182
2229
  };
2183
2230
  }
2184
2231
  /** Determine whether every guide body fits the public UTF-8 artifact byte limit. */
@@ -5554,6 +5601,7 @@ function packageManifest(spec) {
5554
5601
  }
5555
5602
  if (spec.engine) scripts["test:src:bin"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:bin";
5556
5603
  if (spec.engine) scripts["test:integration"] = "vitest run --config vite.config.ts --no-cache --reporter=dot --project integration";
5604
+ if (spec.engine) scripts["test:equivalence"] = "node -e \"const c=require('node:child_process'),n=process.platform==='win32'?'npm.cmd':'npm',r=c.spawnSync(n,['run','test:integration'],{stdio:'inherit',env:{...process.env,SCAFFOLD_BOUNDARY_EQUIVALENCE:'1'}});process.exit(r.status??1)\"";
5557
5605
  if (spec.app.length > 0) {
5558
5606
  scripts["test:app"] = "vitest run --config vite.config.ts --no-cache --reporter=dot " + spec.app.map((environment) => `--project ${APP_MATRIX[environment].project}`).join(" ");
5559
5607
  for (const environment of spec.app) scripts[`test:app:${environment}`] = `vitest run --config vite.config.ts --no-cache --reporter=dot --project ${APP_MATRIX[environment].project}`;
@@ -5714,6 +5762,37 @@ function viteMachinery(src, app = [], engine = false) {
5714
5762
  };
5715
5763
  }
5716
5764
  /**
5765
+ * Render the root Vitest project registration, preserving browser ownership
5766
+ * supplied by the caller.
5767
+ *
5768
+ * @param registrations - Ordered project factory identifiers with optional browser labels.
5769
+ * @param browser - Whether the generated configuration carries browser machinery.
5770
+ * @returns The rendered root `test` property.
5771
+ *
5772
+ * @example
5773
+ * ```ts
5774
+ * renderViteTest([{ project: 'srcCore' }], false)
5775
+ * // '\ttest: {\n\t\tprojects: [srcCore],\n\t},'
5776
+ * ```
5777
+ */
5778
+ function renderViteTest(registrations, browser) {
5779
+ const projects = registrations.map((registration) => registration.project);
5780
+ const inlineProjects = ` projects: [${projects.join(", ")}],`;
5781
+ const renderedProjects = computeColumnWidth(inlineProjects) <= 100 ? inlineProjects : ` projects: [
5782
+ ${projects.map((project) => ` ${project},`).join("\n")}
5783
+ ],`;
5784
+ if (!browser) return ` test: {
5785
+ ${renderedProjects}
5786
+ },`;
5787
+ return ` test: gateBrowserProjects(
5788
+ [
5789
+ ${registrations.map((registration) => registration.browser === void 0 ? `{ project: ${registration.project} }` : `{ project: ${registration.project}, browser: ${serializeTypeScriptString(registration.browser)} }`).map((registration) => ` ${registration},`).join("\n")}
5790
+ ],
5791
+ hasChromium,
5792
+ process.argv,
5793
+ ),`;
5794
+ }
5795
+ /**
5717
5796
  * The rendered import / `resolve` header block every `rootViteConfig` shape
5718
5797
  * prefixes — the environment boundary and every guarantee it enforces ship
5719
5798
  * unconditionally; `machinery` selects only the host-specific pipelines layered
@@ -5751,6 +5830,7 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5751
5830
  transform: {
5752
5831
  order: 'pre',
5753
5832
  async handler(code, id) {
5833
+ if (!isWorkspaceBoundaryModule(id)) return null
5754
5834
  const restored = /[?&]html-proxy(?:[=&]|$)/.test(id) ? restoreIgnoredHtml(code) : code
5755
5835
  const target = workspacePath(id)
5756
5836
  const physicalImporter = physicalPath(id)
@@ -5910,6 +5990,7 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5910
5990
  transform: {
5911
5991
  order: 'pre',
5912
5992
  async handler(code, id) {
5993
+ if (!isWorkspaceBoundaryModule(id)) return null
5913
5994
  const target = workspacePath(id)
5914
5995
  const physicalImporter = physicalPath(id)
5915
5996
  const importerPackageRoot = trustedPackageRootFor(physicalImporter, trustedPackageRoots)
@@ -5992,6 +6073,7 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5992
6073
  transform: {
5993
6074
  order: 'pre',
5994
6075
  async handler(code, id) {
6076
+ if (!isWorkspaceBoundaryModule(id)) return null
5995
6077
  const target = workspacePath(id)
5996
6078
  const physicalImporter = physicalPath(id)
5997
6079
  const importerPackageRoot = trustedPackageRootFor(physicalImporter, trustedPackageRoots)
@@ -6083,6 +6165,64 @@ ${EXPORT_KEYWORD} function workspacePath(path: string): string | undefined {
6083
6165
  return relativePath
6084
6166
  }
6085
6167
 
6168
+ ${EXPORT_KEYWORD} function isBoundaryExemptModule(id: string): boolean {
6169
+ const normalizedId = id.replaceAll('\\\\', '/')
6170
+ const [path] = normalizedId.split(/[?#]/)
6171
+ if (
6172
+ path === undefined ||
6173
+ normalizedId.startsWith('\\0') ||
6174
+ normalizedId.includes('virtual:') ||
6175
+ normalizedId === '@vite/client' ||
6176
+ normalizedId === '@vite/env' ||
6177
+ normalizedId.startsWith('/@id/') ||
6178
+ normalizedId.startsWith('/@vite/') ||
6179
+ normalizedId.startsWith('/__vite') ||
6180
+ normalizedId.startsWith('/__vitest') ||
6181
+ normalizedId.startsWith('@vitest/browser') ||
6182
+ normalizedId.includes('/@vitest/browser/')
6183
+ ) {
6184
+ return true
6185
+ }
6186
+ let physicalId: string | undefined
6187
+ try {
6188
+ physicalId = physicalPath(id).replaceAll('\\\\', '/')
6189
+ } catch {
6190
+ physicalId = undefined
6191
+ }
6192
+ for (const candidate of physicalId === undefined ? [path] : [path, physicalId]) {
6193
+ if (candidate.split('/').some((segment) => segment.toLowerCase() === 'node_modules')) {
6194
+ return true
6195
+ }
6196
+ }
6197
+ return false
6198
+ }
6199
+
6200
+ ${EXPORT_KEYWORD} function isWorkspaceBoundaryModule(id: string): boolean {
6201
+ if (isBoundaryExemptModule(id)) return false
6202
+ const normalizedId = id.replaceAll('\\\\', '/')
6203
+ const [path] = normalizedId.split(/[?#]/)
6204
+ if (path === undefined) return false
6205
+ let candidate = path.startsWith('/@fs/') ? path.slice('/@fs/'.length) : path
6206
+ try {
6207
+ if (/^file:/i.test(candidate)) candidate = fileURLToPath(candidate)
6208
+ } catch {
6209
+ return false
6210
+ }
6211
+ const rootRelative = /^\\/(?:app|src)\\/(?:core|browser|server)\\//.test(candidate)
6212
+ const absoluteCandidate = rootRelative
6213
+ ? resolvePath(WORKSPACE_ROOT, candidate.slice(1))
6214
+ : isAbsolute(candidate)
6215
+ ? candidate
6216
+ : resolvePath(WORKSPACE_ROOT, candidate)
6217
+ const relativeId = relative(WORKSPACE_ROOT, absoluteCandidate).replaceAll('\\\\', '/')
6218
+ return (
6219
+ relativeId !== '..' &&
6220
+ !relativeId.startsWith('../') &&
6221
+ !isAbsolute(relativeId) &&
6222
+ /^(?:app|src)\\/(?:core|browser|server)\\//.test(relativeId)
6223
+ )
6224
+ }
6225
+
6086
6226
  ${EXPORT_KEYWORD} function isOutsideWorkspacePath(path: string): boolean {
6087
6227
  const [pathWithoutQuery] = path.split('?')
6088
6228
  if (pathWithoutQuery === undefined) return false
@@ -6721,6 +6861,7 @@ ${EXPORT_KEYWORD} function finalizeHtml(): Plugin {
6721
6861
  const transformed = await transformWithOxc(code, path)
6722
6862
  const visitor = new Visitor({
6723
6863
  ImportExpression(node) {
6864
+ if (emitted) return
6724
6865
  let value: string | undefined
6725
6866
  if (node.source.type === 'Literal' && typeof node.source.value === 'string') {
6726
6867
  value = node.source.value
@@ -6819,8 +6960,8 @@ ${needsVue ? ` configureServer(server) {
6819
6960
  })
6820
6961
  },
6821
6962
  ` : ""} async resolveId(source, importer) {
6822
- if (importer === undefined) return null
6823
- if (source.startsWith('\\0')) return null
6963
+ if (importer === undefined || !isWorkspaceBoundaryModule(importer)) return null
6964
+ if (isBoundaryExemptModule(source)) return null
6824
6965
  const normalizedSource = source.replaceAll('\\\\', '/')
6825
6966
  const sourceError = environmentSourceError(owner, normalizedSource)
6826
6967
  if (sourceError !== undefined) this.error(sourceError)
@@ -6897,6 +7038,7 @@ ${needsVue ? ` configureServer(server) {
6897
7038
  return null
6898
7039
  },
6899
7040
  async load(id) {
7041
+ if (!isWorkspaceBoundaryModule(id)) return null
6900
7042
  const physicalImporter = physicalPath(id)
6901
7043
  const trustedPackageRoot = trustedPackageRootFor(physicalImporter, trustedPackageRoots)
6902
7044
  const inferredPackageRoot =
@@ -6954,6 +7096,7 @@ ${needsVue ? ` configureServer(server) {
6954
7096
  const physical = physicalPath(
6955
7097
  isAbsolute(original) ? original : resolvePath(environmentRoot, original),
6956
7098
  )
7099
+ if (isBoundaryExemptModule(original) || isBoundaryExemptModule(physical)) continue
6957
7100
  const target = workspacePath(physical)
6958
7101
  if (target === undefined) {
6959
7102
  if (trustedPackageRootFor(physical, trustedPackageRoots) === undefined) {
@@ -6969,6 +7112,7 @@ ${needsVue ? ` configureServer(server) {
6969
7112
  buildEnd(error) {
6970
7113
  if (error !== undefined) return
6971
7114
  for (const id of this.getModuleIds()) {
7115
+ if (!isWorkspaceBoundaryModule(id)) continue
6972
7116
  const target = workspacePath(id)
6973
7117
  if (target === undefined) {
6974
7118
  if (
@@ -7025,7 +7169,58 @@ ${CONST_KEYWORD} resolve = {
7025
7169
  }, {}),
7026
7170
  }
7027
7171
 
7028
- ${needsBrowser ? `${EXPORT_KEYWORD} ${CONST_KEYWORD} ENVIRONMENT_CSS = Object.freeze({
7172
+ ${needsBrowser ? `${EXPORT_KEYWORD} function gateBrowserProjects(
7173
+ registrations: readonly {
7174
+ readonly project: () => UserConfig
7175
+ readonly browser?: string
7176
+ }[],
7177
+ available: boolean,
7178
+ argv: readonly string[],
7179
+ ): NonNullable<UserConfig['test']> {
7180
+ const projects: UserConfig[] = []
7181
+ const gated: string[] = []
7182
+ for (const registration of registrations) {
7183
+ if (registration.browser !== undefined && !available) {
7184
+ gated.push(registration.browser)
7185
+ projects.push({
7186
+ resolve,
7187
+ test: {
7188
+ name: { label: registration.browser, color: 'yellow' },
7189
+ include: [],
7190
+ environment: 'node',
7191
+ browser: { enabled: false },
7192
+ },
7193
+ })
7194
+ continue
7195
+ }
7196
+ projects.push(registration.project())
7197
+ }
7198
+ if (gated.length === 0) return { projects }
7199
+ console.warn(\`browser projects skipped: Chromium absent (\${gated.join(', ')})\`)
7200
+ const filters: string[] = []
7201
+ let readable = true
7202
+ for (let index = 0; index < argv.length; index += 1) {
7203
+ const argument = argv[index]
7204
+ if (argument === '--project') {
7205
+ const filter = argv[index + 1]
7206
+ if (filter === undefined) {
7207
+ readable = false
7208
+ continue
7209
+ }
7210
+ filters.push(filter)
7211
+ index += 1
7212
+ continue
7213
+ }
7214
+ if (argument?.startsWith('--project=') === true) {
7215
+ filters.push(argument.slice('--project='.length))
7216
+ }
7217
+ }
7218
+ return readable && filters.length > 0 && filters.every((filter) => gated.includes(filter))
7219
+ ? { passWithNoTests: true, projects }
7220
+ : { projects }
7221
+ }
7222
+
7223
+ ${EXPORT_KEYWORD} ${CONST_KEYWORD} ENVIRONMENT_CSS = Object.freeze({
7029
7224
  transformer: 'lightningcss',
7030
7225
  lightningcss: {
7031
7226
  visitor: () => {
@@ -7120,11 +7315,10 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7120
7315
  },
7121
7316
  test: {
7122
7317
  name: { label: 'src:browser', color: 'yellow' },
7123
- include: hasChromium ? ['tests/src/browser/**/*.test.ts'] : [],
7124
- passWithNoTests: !hasChromium,
7318
+ include: ['tests/src/browser/**/*.test.ts'],
7125
7319
  setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
7126
7320
  browser: {
7127
- enabled: hasChromium,
7321
+ enabled: true,
7128
7322
  provider: playwright(),
7129
7323
  instances: [{ browser: 'chromium', headless: true }],
7130
7324
  },
@@ -7153,9 +7347,15 @@ ${EXPORT_KEYWORD} const guides = (config?: UserConfig): UserConfig =>
7153
7347
 
7154
7348
  export default defineConfig({
7155
7349
  resolve,
7156
- test: {
7157
- projects: [srcBrowser, policy, guides],
7158
- },
7350
+ test: gateBrowserProjects(
7351
+ [
7352
+ { project: srcBrowser, browser: 'src:browser' },
7353
+ { project: policy },
7354
+ { project: guides },
7355
+ ],
7356
+ hasChromium,
7357
+ process.argv,
7358
+ ),
7159
7359
  })
7160
7360
  `;
7161
7361
  return `${header}
@@ -7275,12 +7475,11 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7275
7475
  },
7276
7476
  test: {
7277
7477
  name: { label: 'src:browser', color: 'yellow' },
7278
- include: hasChromium ? ['tests/src/browser/**/*.test.ts'] : [],
7279
- passWithNoTests: !hasChromium,
7478
+ include: ['tests/src/browser/**/*.test.ts'],
7280
7479
  exclude: ['tests/src/core/**/*.test.ts'],
7281
7480
  setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
7282
7481
  browser: {
7283
- enabled: hasChromium,
7482
+ enabled: true,
7284
7483
  provider: playwright(),
7285
7484
  instances: [{ browser: 'chromium', headless: true }],
7286
7485
  },
@@ -7378,14 +7577,15 @@ ${EXPORT_KEYWORD} const integration = (config?: UserConfig): UserConfig =>
7378
7577
  )
7379
7578
  ` : "";
7380
7579
  const blocks = nonCore.map((environment) => environment === "browser" ? browserBlock : serverBlock).join("") + binBlock;
7381
- const projectNames = [
7382
- ...hasCore ? ["srcCore"] : [],
7383
- ...nonCore.map((environment) => `src${pascalCase(environment)}`),
7384
- "policy",
7385
- "guides",
7386
- ...engine ? ["srcBin"] : [],
7387
- ...engine ? ["integration"] : []
7388
- ];
7580
+ const registrations = [];
7581
+ if (hasCore) registrations.push({ project: "srcCore" });
7582
+ for (const environment of nonCore) registrations.push(environment === "browser" ? {
7583
+ project: "srcBrowser",
7584
+ browser: SRC_MATRIX.browser.project
7585
+ } : { project: "srcServer" });
7586
+ registrations.push({ project: "policy" }, { project: "guides" });
7587
+ if (engine) registrations.push({ project: "srcBin" }, { project: "integration" });
7588
+ const renderedTest = renderViteTest(registrations, machinery.browser);
7389
7589
  return `${header}
7390
7590
  ${EXPORT_KEYWORD} const srcCore = (config?: UserConfig): UserConfig =>
7391
7591
  mergeConfig(
@@ -7425,9 +7625,7 @@ ${EXPORT_KEYWORD} const guides = (config?: UserConfig): UserConfig =>
7425
7625
  ${blocks}
7426
7626
  export default defineConfig({
7427
7627
  resolve,
7428
- test: {
7429
- projects: [${projectNames.join(", ")}],
7430
- },
7628
+ ${renderedTest}
7431
7629
  })
7432
7630
  `;
7433
7631
  }
@@ -7449,10 +7647,10 @@ function applicationViteConfig(src, app, engine = false) {
7449
7647
  const hasSourceCore = src.includes("core");
7450
7648
  const machinery = viteMachinery(src, app, engine);
7451
7649
  const header = viteHeader(machinery);
7452
- const projects = [];
7650
+ const registrations = [];
7453
7651
  const blocks = [];
7454
7652
  if (src.includes("core")) {
7455
- projects.push("srcCore");
7653
+ registrations.push({ project: "srcCore" });
7456
7654
  blocks.push(`
7457
7655
  ${EXPORT_KEYWORD} const srcCore = (config?: UserConfig): UserConfig =>
7458
7656
  mergeConfig(
@@ -7474,7 +7672,10 @@ ${EXPORT_KEYWORD} const srcCore = (config?: UserConfig): UserConfig =>
7474
7672
  `);
7475
7673
  }
7476
7674
  if (src.includes("browser")) {
7477
- projects.push("srcBrowser");
7675
+ registrations.push({
7676
+ project: "srcBrowser",
7677
+ browser: SRC_MATRIX.browser.project
7678
+ });
7478
7679
  const coreOutput = hasSourceCore ? `
7479
7680
  output: { paths: { '@src/core': '../core/index.js' } },` : "";
7480
7681
  const coreExternal = hasSourceCore ? `id === '@src/core' || ` : "";
@@ -7503,11 +7704,10 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7503
7704
  },
7504
7705
  test: {
7505
7706
  name: { label: 'src:browser', color: 'yellow' },
7506
- include: hasChromium ? ['tests/src/browser/**/*.test.ts'] : [],
7507
- passWithNoTests: !hasChromium,
7707
+ include: ['tests/src/browser/**/*.test.ts'],
7508
7708
  ${hasSourceCore ? "exclude: ['tests/src/core/**/*.test.ts'],\n " : ""}setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
7509
7709
  browser: {
7510
- enabled: hasChromium,
7710
+ enabled: true,
7511
7711
  provider: playwright(),
7512
7712
  instances: [{ browser: 'chromium', headless: true }],
7513
7713
  },
@@ -7519,7 +7719,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7519
7719
  `);
7520
7720
  }
7521
7721
  if (src.includes("server")) {
7522
- projects.push("srcServer");
7722
+ registrations.push({ project: "srcServer" });
7523
7723
  const coreOutput = hasSourceCore ? `
7524
7724
  output: [
7525
7725
  {
@@ -7570,7 +7770,7 @@ ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
7570
7770
  `);
7571
7771
  }
7572
7772
  if (app.includes("core")) {
7573
- projects.push("appCore");
7773
+ registrations.push({ project: "appCore" });
7574
7774
  blocks.push(`
7575
7775
  ${EXPORT_KEYWORD} const appCore = (config?: UserConfig): UserConfig =>
7576
7776
  mergeConfig(
@@ -7591,7 +7791,10 @@ ${EXPORT_KEYWORD} const appCore = (config?: UserConfig): UserConfig =>
7591
7791
  `);
7592
7792
  }
7593
7793
  if (app.includes("browser")) {
7594
- projects.push("appBrowser()");
7794
+ registrations.push({
7795
+ project: "appBrowser",
7796
+ browser: APP_MATRIX.browser.project
7797
+ });
7595
7798
  blocks.push(`
7596
7799
  ${EXPORT_KEYWORD} function appBrowser(...config: readonly never[]): UserConfig {
7597
7800
  if (config.length > 0) {
@@ -7632,11 +7835,10 @@ ${EXPORT_KEYWORD} function appBrowser(...config: readonly never[]): UserConfig {
7632
7835
  name: { label: '${APP_MATRIX.browser.project}', color: 'blue' },
7633
7836
  root: resolveWorkspacePath('.'),
7634
7837
  dir: resolveWorkspacePath('.'),
7635
- include: hasChromium ? ['tests/app/browser/**/*.test.ts'] : [],
7636
- passWithNoTests: !hasChromium,
7838
+ include: ['tests/app/browser/**/*.test.ts'],
7637
7839
  setupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],
7638
7840
  browser: {
7639
- enabled: hasChromium,
7841
+ enabled: true,
7640
7842
  provider: playwright(),
7641
7843
  instances: [{ browser: 'chromium', headless: true }],
7642
7844
  },
@@ -7647,7 +7849,7 @@ ${EXPORT_KEYWORD} function appBrowser(...config: readonly never[]): UserConfig {
7647
7849
  `);
7648
7850
  }
7649
7851
  if (app.includes("server")) {
7650
- projects.push("appServer");
7852
+ registrations.push({ project: "appServer" });
7651
7853
  blocks.push(`
7652
7854
  ${EXPORT_KEYWORD} const appServer = (config?: UserConfig): UserConfig =>
7653
7855
  mergeConfig(
@@ -7681,7 +7883,7 @@ ${EXPORT_KEYWORD} const appServer = (config?: UserConfig): UserConfig =>
7681
7883
  `);
7682
7884
  }
7683
7885
  if (engine) {
7684
- projects.push("srcBin", "integration");
7886
+ registrations.push({ project: "srcBin" }, { project: "integration" });
7685
7887
  blocks.push(`
7686
7888
  ${EXPORT_KEYWORD} const srcBin = (config?: UserConfig): UserConfig =>
7687
7889
  mergeConfig(
@@ -7725,6 +7927,8 @@ ${EXPORT_KEYWORD} const integration = (config?: UserConfig): UserConfig =>
7725
7927
  )
7726
7928
  `);
7727
7929
  }
7930
+ registrations.push({ project: "policy" }, { project: "guides" });
7931
+ const renderedTest = renderViteTest(registrations, machinery.browser);
7728
7932
  return `${header}
7729
7933
  ${policyViteProject()}
7730
7934
  ${EXPORT_KEYWORD} const guides = (config?: UserConfig): UserConfig =>
@@ -7745,18 +7949,12 @@ ${EXPORT_KEYWORD} const guides = (config?: UserConfig): UserConfig =>
7745
7949
  ${blocks.join("")}
7746
7950
  export default defineConfig({
7747
7951
  resolve,
7748
- test: {
7749
- projects: [${[
7750
- ...projects,
7751
- "policy",
7752
- "guides"
7753
- ].join(", ")}],
7754
- },
7952
+ ${renderedTest}
7755
7953
  })
7756
7954
  `;
7757
7955
  }
7758
7956
  /**
7759
- * `configs/src/tsconfig.core.json` — unchanged core shape.
7957
+ * `configs/src/tsconfig.core.json` — host-neutral core with web interop declarations.
7760
7958
  *
7761
7959
  * @returns The core environment `tsconfig` file content, newline-terminated.
7762
7960
  *
@@ -7769,7 +7967,7 @@ function coreTsconfig() {
7769
7967
  return formatJson({
7770
7968
  extends: "../../tsconfig.json",
7771
7969
  compilerOptions: {
7772
- lib: ["ESNext"],
7970
+ lib: ["ESNext", "WebWorker"],
7773
7971
  types: [],
7774
7972
  noEmit: false,
7775
7973
  declaration: true,
@@ -7924,7 +8122,7 @@ function appTsconfig(environment, hasCore) {
7924
8122
  "ESNext",
7925
8123
  "DOM",
7926
8124
  "DOM.Iterable"
7927
- ] : ["ESNext"],
8125
+ ] : environment === "core" ? ["ESNext", "WebWorker"] : ["ESNext"],
7928
8126
  types: environment === "browser" ? ["vite/client", "vue"] : environment === "server" ? ["node"] : []
7929
8127
  },
7930
8128
  include
@@ -8526,12 +8724,15 @@ function guideTests(spec, pascal) {
8526
8724
  }
8527
8725
  /**
8528
8726
  * Draft the `guides` group's artifacts — the package's own filled guide stub,
8529
- * the guides index, and any vendored dependency guide mirrors.
8727
+ * the guides index, and vendored dependency guide mirrors whose paths are
8728
+ * neither the package's own guide nor already carried by the selected host
8729
+ * set.
8530
8730
  *
8531
8731
  * @param spec - The `Blueprint` to derive guide artifacts from.
8532
8732
  * @param pascal - The package's PascalCase entity name.
8533
8733
  * @param members - The blueprint's derived `Member[]`.
8534
- * @returns The `guides` group's `Artifact[]`.
8734
+ * @returns The `guides` group's `Artifact[]`, with one contributor per guide
8735
+ * path.
8535
8736
  *
8536
8737
  * @example
8537
8738
  * ```ts
@@ -8584,14 +8785,16 @@ function guideArtifacts(spec, pascal, members) {
8584
8785
  ]]),
8585
8786
  directory: alignTable(["Directory", "Guide"], sourceDirectories.map((directory) => [directory, `[\`${spec.name}.md\`](src/${spec.name}.md)`]))
8586
8787
  })];
8788
+ const guidePath = `guides/src/${spec.name}.md`;
8587
8789
  for (const dep of spec.dependencies) {
8588
8790
  if (!vendoredGuides.includes(dep.name)) continue;
8589
- const short = dep.name.replace("@orkestrel/", "");
8791
+ const path = `guides/src/${dep.name.replace("@orkestrel/", "")}.md`;
8792
+ if (HOST_PATHS.includes(path) || path === guidePath) continue;
8590
8793
  artifacts.push({
8591
- path: `guides/src/${short}.md`,
8794
+ path,
8592
8795
  group: "guides",
8593
8796
  origin: "host",
8594
- source: `guides/src/${short}.md`
8797
+ source: path
8595
8798
  });
8596
8799
  }
8597
8800
  return artifacts;
@@ -8627,7 +8830,7 @@ function applyOverrides(artifacts, overrides) {
8627
8830
  /**
8628
8831
  * The full pure compilation: draft a blueprint's artifacts — the manifest and
8629
8832
  * exports combination rules over the per-environment `SRC_MATRIX` rows, plus
8630
- * `HOST_PATHS` and `overrides` — then pin.
8833
+ * the `selectHostPaths` selection of `HOST_PATHS` and `overrides` — then pin.
8631
8834
  *
8632
8835
  * @param blueprint - The `Blueprint` to compile.
8633
8836
  * @param groups - An optional `Group[]` selection (default: all groups).
@@ -8671,7 +8874,7 @@ npm install @orkestrel/${blueprint.name}
8671
8874
  origin: "computed",
8672
8875
  content: ciWorkflow(blueprint)
8673
8876
  });
8674
- for (const path of HOST_PATHS) {
8877
+ for (const path of selectHostPaths(HOST_PATHS, blueprint.name)) {
8675
8878
  const group = hostGroup(path);
8676
8879
  if (!selected.includes(group)) continue;
8677
8880
  artifacts.push({
@@ -8794,7 +8997,10 @@ var Compiler = class Compiler {
8794
8997
  this.#emitter.emit("audit", result);
8795
8998
  return result;
8796
8999
  }
8797
- const result = diffPlan(scaffolding.plan, current);
9000
+ const result = {
9001
+ ...diffPlan(scaffolding.plan, current),
9002
+ questions: scaffolding.questions
9003
+ };
8798
9004
  this.#emitter.emit("audit", result);
8799
9005
  return result;
8800
9006
  }
@@ -8858,7 +9064,16 @@ var Compiler = class Compiler {
8858
9064
  const validation = validatePlan(draft);
8859
9065
  const dependencyQuestions = this.#dependencyQuestions(blueprint);
8860
9066
  const blocking = [...validation.questions];
8861
- const questions = [...blocking, ...dependencyQuestions];
9067
+ const warningQuestions = validation.warnings.map((text) => ({
9068
+ field: "overrides",
9069
+ text,
9070
+ blocking: false
9071
+ }));
9072
+ const questions = [
9073
+ ...blocking,
9074
+ ...warningQuestions,
9075
+ ...dependencyQuestions
9076
+ ];
8862
9077
  stages.push({
8863
9078
  stage: "gate",
8864
9079
  input: draft,
@@ -8951,9 +9166,11 @@ var Compiler = class Compiler {
8951
9166
  }
8952
9167
  #pointerArtifacts(blueprint) {
8953
9168
  const artifacts = [];
9169
+ const guidePath = `guides/src/${blueprint.name}.md`;
8954
9170
  for (const item of blueprint.dependencies) {
8955
9171
  if (Compiler.#vendored.includes(item.name)) continue;
8956
9172
  const path = `guides/src/${item.name.replace("@orkestrel/", "")}.md`;
9173
+ if (path === guidePath || HOST_PATHS.includes(path)) continue;
8957
9174
  artifacts.push({
8958
9175
  path,
8959
9176
  group: "guides",
@@ -9178,6 +9395,6 @@ function createBlueprint(data) {
9178
9395
  return candidate;
9179
9396
  }
9180
9397
  //#endregion
9181
- export { APP_BROWSER_DEV_DEPENDENCIES, APP_MATRIX, BASE_DEV_DEPENDENCIES, CATEGORIES, CHECKOUT_ACTION_SHA, COMPILER_ID, COMPILE_STAGES, CONST_KEYWORD, CONTROL_CHARACTER_PATTERN, Compiler, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENGINES_PATTERN, ENVIRONMENTS, EXPORT_KEYWORD, EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN, FRESHNESS, FUNCTION_KEYWORD, GROUPS, HEX_PATTERN, HOST_PATHS, IMPORT_KEYWORD, INVALID_PATH_CHARACTER_PATTERN, JSON_PRINT_WIDTH, JSON_TAB_WIDTH, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_COLLECTION_ITEMS, MAX_DATA_GRAPH_KEYS, MAX_DATA_GRAPH_NODES, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_SERIALIZED_INPUT_BYTES, MAX_TOTAL_ARTIFACT_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORIGINS, ORKESTREL_RANGE_PATTERN, PlanManager, SCAFFOLD_RANGE, SETUP_NODE_ACTION_SHA, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, SYNC_BASELINE_PATTERN, ScaffoldError, TEMPLATES, TYPESCRIPT_EXTENSIONS, VERSION_PATTERN, alignTable, appTsconfig, appViteConfig, applicationArtifacts, applicationViteConfig, applyOverrides, artifactShape, auditToReview, blueprint, blueprintShape, blueprintToMembers, blueprintToPlan, bytesToHex, catalogNames, catalogToBlock, ciWorkflow, compareCodeUnit, computeColumnWidth, computeHash, configArtifacts, contentByteLength, contentCodePoint, contentToBytes, contentToHex, coreTsconfig, coreViteConfig, createBlueprint, createCompiler, createPlanManager, delimiterCell, dependency, dependencyShape, devDependenciesFor, diffPlan, dualCondition, entryFields, escapeHtmlText, exportsMap, fillArtifact, findFileConflict, findPathConflict, formatJson, guideArtifacts, guideMemberTable, guideMethods, guideTests, guideUsage, hasBlueprintEnvironment, hasOnlyDataProperties, hasValidArtifactBytes, hasValidArtifactHex, hasValidAuditBytes, hasValidBlueprintBytes, hasValidOverrideBytes, hasValidPlanBytes, hasValidPlanHex, hasValidSnapshotBytes, hasValidSyncReportBytes, hostGroup, inferGroup, isArtifact, isBehind, isBlueprint, isCompilerEventHooks, isDenseDataArray, isDependency, isEmitterErrorHandler, isMember, isOverride, isPlan, isPlanManagerEventHooks, isScaffoldError, isSyncReport, isWorkspaceName, manifestToDependencies, member, memberShape, override, overrideShape, ownDataValue, packageManifest, padCell, paritySpecifiers, parseBlueprint, parseBoundedJSON, parseCompilerOptions, parsePlan, parsePlanIds, parsePlanManagerOptions, parseSyncReport, pascalCase, pinPlan, planPayload, planShape, planToReview, planToSummary, policyViteProject, rangeToFreshness, renderArray, renderObject, renderValue, rootTsconfig, rootViteConfig, serializeTypeScriptString, singleSrcViteConfig, snapshotOf, snapshotPlan, sourceArtifacts, splitTableRow, srcTsconfig, srcVariant, srcViteConfig, stableStringify, syncReportShape, syncToReview, testArtifacts, validateBlueprint, validateDependencyArray, validatePlan, viteHeader, viteMachinery };
9398
+ export { APP_BROWSER_DEV_DEPENDENCIES, APP_MATRIX, BASE_DEV_DEPENDENCIES, CATEGORIES, CHECKOUT_ACTION_SHA, COMPILER_ID, COMPILE_STAGES, CONST_KEYWORD, CONTROL_CHARACTER_PATTERN, Compiler, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENGINES_PATTERN, ENVIRONMENTS, EXPORT_KEYWORD, EXTRA_NAME_PATTERN, EXTRA_RANGE_PATTERN, FRESHNESS, FUNCTION_KEYWORD, GROUPS, HEX_PATTERN, HOST_PATHS, IMPORT_KEYWORD, INVALID_PATH_CHARACTER_PATTERN, JSON_PRINT_WIDTH, JSON_TAB_WIDTH, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_COLLECTION_ITEMS, MAX_DATA_GRAPH_KEYS, MAX_DATA_GRAPH_NODES, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_NAME_LENGTH, MAX_PATH_LENGTH, MAX_RANGE_LENGTH, MAX_SERIALIZED_INPUT_BYTES, MAX_TOTAL_ARTIFACT_BYTES, MINIMUM_NODE_VERSION, NAME_PATTERN, ORIGINS, ORKESTREL_RANGE_PATTERN, PlanManager, SCAFFOLD_RANGE, SETUP_NODE_ACTION_SHA, SOURCE_BROWSER_DEV_DEPENDENCIES, SRC_MATRIX, SYNC_BASELINE_PATTERN, ScaffoldError, TEMPLATES, TYPESCRIPT_EXTENSIONS, VERSION_PATTERN, alignTable, appTsconfig, appViteConfig, applicationArtifacts, applicationViteConfig, applyOverrides, artifactShape, auditToReview, blueprint, blueprintShape, blueprintToMembers, blueprintToPlan, bytesToHex, catalogNames, catalogToBlock, ciWorkflow, compareCodeUnit, computeColumnWidth, computeHash, configArtifacts, contentByteLength, contentCodePoint, contentToBytes, contentToHex, coreTsconfig, coreViteConfig, createBlueprint, createCompiler, createPlanManager, delimiterCell, dependency, dependencyShape, devDependenciesFor, diffPlan, dualCondition, entryFields, escapeHtmlText, exportsMap, fillArtifact, findFileConflict, findPathConflict, formatJson, guideArtifacts, guideMemberTable, guideMethods, guideTests, guideUsage, hasBlueprintEnvironment, hasOnlyDataProperties, hasValidArtifactBytes, hasValidArtifactHex, hasValidAuditBytes, hasValidBlueprintBytes, hasValidOverrideBytes, hasValidPlanBytes, hasValidPlanHex, hasValidSnapshotBytes, hasValidSyncReportBytes, hostGroup, inferGroup, isArtifact, isBehind, isBlueprint, isCompilerEventHooks, isDenseDataArray, isDependency, isEmitterErrorHandler, isMember, isOverride, isPlan, isPlanManagerEventHooks, isScaffoldError, isSyncReport, isWorkspaceName, manifestToDependencies, manifestToName, member, memberShape, override, overrideShape, ownDataValue, packageManifest, padCell, paritySpecifiers, parseBlueprint, parseBoundedJSON, parseCompilerOptions, parsePlan, parsePlanIds, parsePlanManagerOptions, parseSyncReport, pascalCase, pinPlan, planPayload, planShape, planToReview, planToSummary, policyViteProject, rangeToFreshness, renderArray, renderObject, renderValue, renderViteTest, rootTsconfig, rootViteConfig, selectHostPaths, serializeTypeScriptString, singleSrcViteConfig, snapshotOf, snapshotPlan, sourceArtifacts, splitTableRow, srcTsconfig, srcVariant, srcViteConfig, stableStringify, syncReportShape, syncToReview, testArtifacts, validateBlueprint, validateDependencyArray, validatePlan, viteHeader, viteMachinery };
9182
9399
 
9183
9400
  //# sourceMappingURL=index.js.map