@orkestrel/scaffold 0.0.4 → 0.0.5

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.
@@ -81,6 +81,22 @@ shared-file edits, and tree-wide mutating gates. Return the touched files,
81
81
  diffstat, scoped validation, and deviation state for independent integration and
82
82
  review.
83
83
 
84
+ ## Routing exclusion — defensive negative-test units
85
+
86
+ The provider applies a content-safety filter that terminates a turn mid-run when
87
+ the work requires authoring or reproducing a violation construct, even when the
88
+ purpose is to prove a guard REJECTS it: sandbox escapes, resolution-bypassing
89
+ imports, boundary evasion, injection payloads, credential-handling probes. The
90
+ filter reads the construct, not the intent, so a legitimate negative test trips
91
+ it exactly like an attack would. Observed twice on one unit, at the same point in
92
+ the work, with nothing written to disk either time.
93
+
94
+ Route such a unit to the native Opus `implementer` from the start, and record the
95
+ Codex bench dark for that unit with this reason. Do not soften or obscure a brief
96
+ to slip past the filter — a bench that declines work is a routing fact, not an
97
+ obstacle. The exclusion is per unit: everything else still routes to Sol
98
+ normally, and an audit that merely READS existing negative tests is unaffected.
99
+
84
100
  ## Journals and Windows
85
101
 
86
102
  - Journals, briefs, session files, and last-message files under `tmp/codex/` are
@@ -133,6 +133,7 @@ From [`types.ts`](../../src/core/types.ts).
133
133
  | `BuildFormat` | type |
134
134
  | `SrcDefinition` | interface |
135
135
  | `AppDefinition` | interface |
136
+ | `ViteMachinery` | interface |
136
137
  | `Origin` | type |
137
138
  | `Group` | type |
138
139
  | `Category` | type |
@@ -183,6 +184,12 @@ is `'INVALID' | 'BLOCKED' | 'DESTROYED' | 'TARGET' | 'WRITE' | 'FETCH'`.
183
184
  environment contributes, its test-project label, and — on the `src` axis — its `exports` subpath
184
185
  and build formats, or — on the `app` axis — its optional runtime entry.
185
186
 
187
+ `ViteMachinery` names the three host-specific pipelines a workspace's generated `vite.config.ts` may
188
+ carry: `browser` for the CSS pipeline and the Playwright-backed browser test project, `vue` for the
189
+ single-file-component, HTML, and development-server machinery an application browser environment
190
+ needs, and `output` for build-output containment. It never selects a boundary guarantee — those ship
191
+ in every shape, as the compilers section sets out.
192
+
186
193
  `Blueprint` is the closed input spec:
187
194
 
188
195
  ```ts
@@ -946,6 +953,7 @@ From [`compilers.ts`](../../src/core/compilers.ts).
946
953
  | `devDependenciesFor` | function |
947
954
  | `packageManifest` | function |
948
955
  | `rootTsconfig` | function |
956
+ | `viteMachinery` | function |
949
957
  | `viteHeader` | function |
950
958
  | `policyViteProject` | function |
951
959
  | `singleSrcViteConfig` | function |
@@ -987,10 +995,33 @@ optional metadata, and engines.
987
995
  `rootTsconfig` emits the root compiler options and one path alias per declared environment;
988
996
  `coreTsconfig`, `srcTsconfig`, and `appTsconfig` emit the scoped configurations that remove the
989
997
  wrong host's globals from each environment. `viteHeader` renders the shared header — the alias block
990
- derived from the tsconfig paths, plus the environment-boundary plugin. `coreViteConfig`,
991
- `srcViteConfig`, and `appViteConfig` emit the thin per-target wrappers; `rootViteConfig`,
992
- `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for a
993
- library-only, single non-core `src` environment, and application-bearing workspace respectively;
998
+ derived from the tsconfig paths, plus the environment-boundary plugin — and `viteMachinery` is the
999
+ one place the header's axes are derived, read by `rootViteConfig`, `singleSrcViteConfig`,
1000
+ `applicationViteConfig`, and `configArtifacts` alike so no caller can invent a fourth answer.
1001
+
1002
+ **The boundary guarantees do not vary by blueprint.** Every generated `vite.config.ts` — a
1003
+ `core`-only library, an application of `app/core` alone, or the full six-environment workspace —
1004
+ emits `environmentBoundary`, its `resolveId` / `load` / `buildEnd` walks, the module-graph AST audit
1005
+ (`environmentAssetSources`, `parseSync`, `Visitor`), and stylesheet rejection (`isStylesheetPath`
1006
+ plus its `environmentPathError` / `environmentSourceError` clauses). Those enforce owner-independent
1007
+ laws: core stays host-independent whatever else the workspace declares, a server module never
1008
+ imports a stylesheet, and a `@vite-ignore` dynamic import — which `resolveId` never sees and the
1009
+ module graph never records — has no other enforcement point. Only host-specific pipelines vary,
1010
+ along the three `ViteMachinery` axes:
1011
+
1012
+ | Machinery | Emitted when |
1013
+ | ----------------------------------------------------------------- | ------------------------------------ |
1014
+ | CSS pipeline (`ENVIRONMENT_CSS`, `preprocessCSS`, `isCSSRequest`) | a `src` or `app` browser environment |
1015
+ | Playwright provider and `hasChromium` | a `src` or `app` browser environment |
1016
+ | Vue plugin, HTML boundary, browser development server | an `app` browser environment |
1017
+ | Output containment (`outputBoundary`, `enforceOutputPath`) | anything the workspace builds |
1018
+
1019
+ An application of `app/core` alone is the sole shape that builds nothing, so it is the sole shape
1020
+ without output containment — and it still carries every boundary guarantee above.
1021
+
1022
+ `coreViteConfig`, `srcViteConfig`, and `appViteConfig` emit the thin per-target wrappers;
1023
+ `rootViteConfig`, `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for
1024
+ a library-only, single non-core `src` environment, and application-bearing workspace respectively;
994
1025
  `policyViteProject` emits the dedicated Node-only repository-policy test project.
995
1026
 
996
1027
  `configArtifacts`, `sourceArtifacts`, `applicationArtifacts`, `testArtifacts`, and `guideArtifacts`
@@ -1924,6 +1955,7 @@ import {
1924
1955
  srcTsconfig,
1925
1956
  srcViteConfig,
1926
1957
  viteHeader,
1958
+ viteMachinery,
1927
1959
  } from '@orkestrel/scaffold'
1928
1960
 
1929
1961
  rootTsconfig(['core'], ['core', 'server'])
@@ -1931,7 +1963,9 @@ coreTsconfig()
1931
1963
  srcTsconfig('server')
1932
1964
  appTsconfig('browser', true)
1933
1965
 
1934
- viteHeader(true, true) // the shared header, with browser and Vue support
1966
+ viteMachinery(['core']) // { browser: false, vue: false, output: true }
1967
+ viteMachinery([], ['core', 'browser']) // { browser: true, vue: true, output: true }
1968
+ viteHeader(viteMachinery([], ['core', 'browser'])) // the shared header, with browser and Vue support
1935
1969
  coreViteConfig()
1936
1970
  srcViteConfig('browser')
1937
1971
  appViteConfig('server')
@@ -218,7 +218,7 @@ var DEFAULT_VERSION = "0.0.1";
218
218
  /** The `engines.node` range the `blueprint` builder fills. */
219
219
  var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
220
220
  /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
221
- var SCAFFOLD_RANGE = "^0.0.4";
221
+ var SCAFFOLD_RANGE = "^0.0.5";
222
222
  /** Tooling versions shared by scaffold and every generated workspace. */
223
223
  var BASE_DEV_DEPENDENCIES = Object.freeze({
224
224
  "@microsoft/api-extractor": "^7.58.12",
@@ -5685,30 +5685,69 @@ function rootTsconfig(src, app = []) {
5685
5685
  });
5686
5686
  }
5687
5687
  /**
5688
+ * Derive which host-specific machinery a workspace's generated root
5689
+ * `vite.config.ts` carries from its declared environments.
5690
+ *
5691
+ * @remarks
5692
+ * This is the SOLE derivation of that set; `rootViteConfig`,
5693
+ * `singleSrcViteConfig`, `applicationViteConfig`, and `configArtifacts` all
5694
+ * read it rather than recomputing an axis of their own. Nothing here selects
5695
+ * a boundary GUARANTEE — the environment-boundary plugin, its module-graph
5696
+ * AST audit, and stylesheet rejection ship in every shape.
5697
+ *
5698
+ * @param src - The declared published `Environment[]`.
5699
+ * @param app - The declared application `Environment[]`, defaulting to none.
5700
+ * @param engine - Whether the workspace also builds its own executable.
5701
+ * @returns The machinery set the generated header renders.
5702
+ *
5703
+ * @example
5704
+ * ```ts
5705
+ * viteMachinery(['core']) // { browser: false, vue: false, output: true }
5706
+ * viteMachinery([], ['core']) // { browser: false, vue: false, output: false }
5707
+ * ```
5708
+ */
5709
+ function viteMachinery(src, app = [], engine = false) {
5710
+ const unbuilt = src.length === 0 && app.length > 0 && !engine && app.every((environment) => environment === "core");
5711
+ return {
5712
+ browser: src.includes("browser") || app.includes("browser"),
5713
+ vue: app.includes("browser"),
5714
+ output: !unbuilt
5715
+ };
5716
+ }
5717
+ /**
5688
5718
  * The rendered import / `resolve` header block every `rootViteConfig` shape
5689
- * prefixes — the official Playwright provider import appears only when
5690
- * `needsPlaywright`, per the three grounded `rootViteConfig`
5691
- * shapes: unconditional for a multi-environment blueprint, conditional on the
5692
- * sole environment being `'browser'` for a single non-`core` environment, absent for
5693
- * `core`-only.
5694
- *
5695
- * @param needsPlaywright - Whether this shape ships a browser test project (and so needs Playwright).
5696
- * @param needsVue - Whether the generated root imports the Vue Vite plugin.
5719
+ * prefixes — the environment boundary and every guarantee it enforces ship
5720
+ * unconditionally; `machinery` selects only the host-specific pipelines layered
5721
+ * over them, per the three grounded `rootViteConfig` shapes: browser machinery
5722
+ * unconditional for a multi-environment blueprint carrying `browser`,
5723
+ * conditional on the sole environment being `'browser'` for a single non-`core`
5724
+ * environment, absent for `core`-only.
5725
+ *
5726
+ * @param machinery - The host-specific machinery this shape carries, from `viteMachinery`.
5697
5727
  * @returns The rendered header block, newline-terminated.
5698
5728
  *
5699
5729
  * @example
5700
5730
  * ```ts
5701
- * viteHeader(false).includes('@vitest/browser-playwright') // false
5702
- * viteHeader(true).includes('@vitest/browser-playwright') // true
5731
+ * viteHeader(viteMachinery(['core'])).includes('@vitest/browser-playwright') // false
5732
+ * viteHeader(viteMachinery(['core', 'browser'])).includes('@vitest/browser-playwright') // true
5703
5733
  * ```
5704
5734
  */
5705
- function viteHeader(needsPlaywright, needsVue = false) {
5706
- const playwrightImports = needsPlaywright ? `import { playwright } from '@vitest/browser-playwright'
5735
+ function viteHeader(machinery) {
5736
+ const { browser: needsBrowser, vue: needsVue, output: needsOutput } = machinery;
5737
+ const playwrightImports = needsBrowser ? `import { playwright } from '@vitest/browser-playwright'
5707
5738
  import { chromium } from 'playwright'
5708
5739
  ` : "";
5709
5740
  const vueImports = needsVue ? `import vue from '@vitejs/plugin-vue'
5710
5741
  import { parse as parseVue } from 'vue/compiler-sfc'
5711
5742
  ` : "";
5743
+ const viteTypeImports = needsVue ? `import type {
5744
+ CSSOptions,
5745
+ HtmlAssetSource,
5746
+ HTMLOptions,
5747
+ Plugin,
5748
+ ResolvedConfig,
5749
+ UserConfig,
5750
+ } from 'vite'` : needsBrowser ? `import type { CSSOptions, Plugin, ResolvedConfig, UserConfig } from 'vite'` : `import type { Plugin, UserConfig } from 'vite'`;
5712
5751
  const vueBoundary = needsVue ? `,
5713
5752
  transform: {
5714
5753
  order: 'pre',
@@ -5868,11 +5907,10 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5868
5907
  }
5869
5908
  return restored === code ? null : restored
5870
5909
  },
5871
- }` : `,
5910
+ }` : needsBrowser ? `,
5872
5911
  transform: {
5873
5912
  order: 'pre',
5874
5913
  async handler(code, id) {
5875
- const restored = /[?&]html-proxy(?:[=&]|$)/.test(id) ? restoreIgnoredHtml(code) : code
5876
5914
  const target = workspacePath(id)
5877
5915
  const physicalImporter = physicalPath(id)
5878
5916
  const importerPackageRoot = trustedPackageRootFor(physicalImporter, trustedPackageRoots)
@@ -5886,15 +5924,13 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5886
5924
  }
5887
5925
  const environmentModule =
5888
5926
  target !== undefined && /^(?:app|src)\\/(?:core|browser|server)\\//.test(target)
5889
- if (!environmentModule && importerPackageRoot === undefined) {
5890
- return restored === code ? null : restored
5891
- }
5927
+ if (!environmentModule && importerPackageRoot === undefined) return null
5892
5928
  if (isCSSRequest(id)) {
5893
5929
  const config = resolvedConfig
5894
5930
  if (config === undefined) {
5895
5931
  this.error('Environment boundary requires resolved Vite configuration')
5896
5932
  }
5897
- const stylesheet = await preprocessCSS(restored, id, config)
5933
+ const stylesheet = await preprocessCSS(code, id, config)
5898
5934
  for (const dependency of stylesheet.deps ?? []) {
5899
5935
  const physicalDependency = physicalPath(dependency)
5900
5936
  const dependencyTarget = workspacePath(physicalDependency)
@@ -5908,7 +5944,7 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5908
5944
  if (dependencyError !== undefined) this.error(dependencyError)
5909
5945
  }
5910
5946
  }
5911
- for (const source of await environmentAssetSources(restored, id)) {
5947
+ for (const source of await environmentAssetSources(code, id)) {
5912
5948
  const normalizedSource = source.replaceAll('\\\\', '/')
5913
5949
  const sourceError = environmentSourceError(owner, normalizedSource)
5914
5950
  if (sourceError !== undefined) this.error(sourceError)
@@ -5951,12 +5987,74 @@ import { parse as parseVue } from 'vue/compiler-sfc'
5951
5987
  const assetError = environmentPathError(owner, resolvedSource)
5952
5988
  if (assetError !== undefined) this.error(assetError)
5953
5989
  }
5954
- return restored === code ? null : restored
5990
+ return null
5991
+ },
5992
+ }` : `,
5993
+ transform: {
5994
+ order: 'pre',
5995
+ async handler(code, id) {
5996
+ const target = workspacePath(id)
5997
+ const physicalImporter = physicalPath(id)
5998
+ const importerPackageRoot = trustedPackageRootFor(physicalImporter, trustedPackageRoots)
5999
+ if (target === undefined) {
6000
+ if (isOutsideWorkspacePath(id) && importerPackageRoot === undefined) {
6001
+ this.error('Environment modules cannot import files outside the workspace')
6002
+ }
6003
+ } else {
6004
+ const pathError = environmentPathError(owner, target)
6005
+ if (pathError !== undefined) this.error(pathError)
6006
+ }
6007
+ const environmentModule =
6008
+ target !== undefined && /^(?:app|src)\\/(?:core|browser|server)\\//.test(target)
6009
+ if (!environmentModule && importerPackageRoot === undefined) return null
6010
+ for (const source of await environmentAssetSources(code, id)) {
6011
+ const normalizedSource = source.replaceAll('\\\\', '/')
6012
+ const sourceError = environmentSourceError(owner, normalizedSource)
6013
+ if (sourceError !== undefined) this.error(sourceError)
6014
+ const [sourcePath] = normalizedSource.split(/[?#]/)
6015
+ if (sourcePath !== undefined && isBuiltin(sourcePath)) continue
6016
+ const resolution = await this.resolve(normalizedSource, id, { skipSelf: true })
6017
+ const fallbackSource = sourceFallback(physicalImporter, normalizedSource)
6018
+ const physicalSource = physicalPath(resolution?.id ?? fallbackSource)
6019
+ if (importerPackageRoot !== undefined) {
6020
+ const pathLike =
6021
+ normalizedSource.startsWith('.') ||
6022
+ normalizedSource.startsWith('/') ||
6023
+ /^file:/i.test(normalizedSource) ||
6024
+ /^[A-Za-z]:[\\\\/]/.test(normalizedSource)
6025
+ if (pathLike && !containedPath(importerPackageRoot, physicalSource)) {
6026
+ this.error(
6027
+ 'Dependency modules cannot import files outside their physical package root',
6028
+ )
6029
+ }
6030
+ if (!pathLike && !containedPath(importerPackageRoot, physicalSource)) {
6031
+ const packageName = packageNameOf(normalizedSource)
6032
+ const packageRoot = normalizedSource.startsWith('#')
6033
+ ? workspacePath(physicalSource) === undefined
6034
+ ? packageRootForResolved(physicalSource)
6035
+ : undefined
6036
+ : packageName === undefined
6037
+ ? undefined
6038
+ : packageRootOf(packageName, physicalSource)
6039
+ if (packageRoot === undefined || !containedPath(packageRoot, physicalSource)) {
6040
+ this.error('Resolved dependencies must remain inside their physical package root')
6041
+ }
6042
+ trustedPackageRoots.add(packageRoot)
6043
+ }
6044
+ continue
6045
+ }
6046
+ const resolvedSource = workspacePath(physicalSource)
6047
+ if (resolvedSource === undefined) {
6048
+ this.error('Environment modules cannot import files outside the workspace')
6049
+ }
6050
+ const assetError = environmentPathError(owner, resolvedSource)
6051
+ if (assetError !== undefined) this.error(assetError)
6052
+ }
6053
+ return null
5955
6054
  },
5956
6055
  }`;
5957
6056
  const environmentBoundary = `
5958
- ${CONST_KEYWORD} WORKSPACE_ROOT = realpathSync.native(dirname(fileURLToPath(import.meta.url)))
5959
- ${EXPORT_KEYWORD} ${CONST_KEYWORD} IMPORT_META_ENV_PREFIX = 'import.meta.env.'
6057
+ ${CONST_KEYWORD} WORKSPACE_ROOT = realpathSync.native(dirname(fileURLToPath(import.meta.url)))${needsVue ? `\n${EXPORT_KEYWORD} ${CONST_KEYWORD} IMPORT_META_ENV_PREFIX = 'import.meta.env.'` : ""}
5960
6058
 
5961
6059
  ${EXPORT_KEYWORD} function physicalPath(path: string): string {
5962
6060
  const [pathWithoutQuery] = path.split('?')
@@ -6001,9 +6099,9 @@ ${EXPORT_KEYWORD} function containedPath(root: string, target: string): boolean
6001
6099
  relativePath === '' ||
6002
6100
  (relativePath !== '..' && !relativePath.startsWith(\`..\${sep}\`) && !isAbsolute(relativePath))
6003
6101
  )
6004
- }
6102
+ }${needsVue ? `
6005
6103
 
6006
- ${needsVue ? `${EXPORT_KEYWORD} function browserServerRoots(): readonly string[] {
6104
+ ${EXPORT_KEYWORD} function browserServerRoots(): readonly string[] {
6007
6105
  const roots: string[] = []
6008
6106
  for (const path of [
6009
6107
  'app/browser',
@@ -6285,7 +6383,7 @@ ${EXPORT_KEYWORD} function environmentSourceError(owner: string, source: string)
6285
6383
  return undefined
6286
6384
  }
6287
6385
 
6288
- ${EXPORT_KEYWORD} function stylesheetAssetError(
6386
+ ${needsBrowser ? `${EXPORT_KEYWORD} function stylesheetAssetError(
6289
6387
  source: string | undefined,
6290
6388
  value: string,
6291
6389
  ): string | undefined {
@@ -6332,7 +6430,7 @@ ${EXPORT_KEYWORD} function stylesheetAssetError(
6332
6430
  return undefined
6333
6431
  }
6334
6432
 
6335
- ${EXPORT_KEYWORD} function enforceOutputPath(configured: string, expected: string): void {
6433
+ ` : ""}${needsOutput ? `${EXPORT_KEYWORD} function enforceOutputPath(configured: string, expected: string): void {
6336
6434
  if (relative(expected, configured) !== '') {
6337
6435
  throw new Error(
6338
6436
  '[orkestrel-output-boundary] Build output must use its exact configured workspace directory',
@@ -6399,7 +6497,7 @@ ${EXPORT_KEYWORD} function outputBoundary(output: string): Plugin {
6399
6497
  }
6400
6498
  }
6401
6499
 
6402
- ${EXPORT_KEYWORD} function decodeAssetSource(source: string): string | undefined {
6500
+ ` : ""}${EXPORT_KEYWORD} function decodeAssetSource(source: string): string | undefined {
6403
6501
  try {
6404
6502
  return decodeURI(source)
6405
6503
  } catch {
@@ -6407,7 +6505,7 @@ ${EXPORT_KEYWORD} function decodeAssetSource(source: string): string | undefined
6407
6505
  }
6408
6506
  }
6409
6507
 
6410
- ${EXPORT_KEYWORD} function filterHtmlAssetSource(
6508
+ ${needsVue ? `${EXPORT_KEYWORD} function filterHtmlAssetSource(
6411
6509
  data: Parameters<NonNullable<HtmlAssetSource['filter']>>[0],
6412
6510
  ): boolean {
6413
6511
  const decoded = decodeAssetSource(data.value)
@@ -6552,7 +6650,7 @@ ${EXPORT_KEYWORD} function maskIgnoredHtml(environmentKeys: ReadonlySet<string>,
6552
6650
  )
6553
6651
  }
6554
6652
 
6555
- ${EXPORT_KEYWORD} function restoreIgnoredHtml(code: string): string {
6653
+ ` : ""}${needsVue ? `${EXPORT_KEYWORD} function restoreIgnoredHtml(code: string): string {
6556
6654
  const literals = code.replace(
6557
6655
  /(?<prefix>[vV][iI][tT][eE])&#45;(?<suffix>[iI][gG][nN][oO][rR][eE])/gu,
6558
6656
  '$<prefix>-$<suffix>',
@@ -6608,7 +6706,7 @@ ${EXPORT_KEYWORD} function finalizeHtml(): Plugin {
6608
6706
  }
6609
6707
  }
6610
6708
 
6611
- ${EXPORT_KEYWORD} async function environmentAssetSources(
6709
+ ` : ""}${EXPORT_KEYWORD} async function environmentAssetSources(
6612
6710
  code: string,
6613
6711
  id: string,
6614
6712
  emitted = false,
@@ -6693,23 +6791,19 @@ ${EXPORT_KEYWORD} async function environmentAssetSources(
6693
6791
  }
6694
6792
  },
6695
6793
  })
6696
- visitor.visit(parseAst(transformed.code, null, path))
6794
+ visitor.visit(parseSync(path, transformed.code).program)
6697
6795
  return sources
6698
6796
  }
6699
6797
 
6700
6798
  ${EXPORT_KEYWORD} function environmentBoundary(
6701
6799
  owner: 'src/core' | 'src/browser' | 'src/server' | 'app/core' | 'app/browser' | 'app/server',
6702
6800
  ): Plugin {
6703
- const trustedPackageRoots = new Set<string>()
6704
- let environmentRoot = WORKSPACE_ROOT
6705
- let resolvedConfig: ResolvedConfig | undefined
6801
+ const trustedPackageRoots = new Set<string>()${needsOutput ? "\n let environmentRoot = WORKSPACE_ROOT" : ""}${needsBrowser ? "\n let resolvedConfig: ResolvedConfig | undefined" : ""}
6706
6802
  return {
6707
6803
  name: 'orkestrel-environment-boundary',
6708
- enforce: 'pre',
6709
- configResolved(config) {
6710
- environmentRoot = physicalPath(config.root)
6711
- resolvedConfig = config
6712
- },
6804
+ enforce: 'pre',${needsOutput || needsBrowser ? `
6805
+ configResolved(config) {${needsOutput ? "\n environmentRoot = physicalPath(config.root)" : ""}${needsBrowser ? "\n resolvedConfig = config" : ""}
6806
+ },` : ""}
6713
6807
  ${needsVue ? ` configureServer(server) {
6714
6808
  if (owner !== 'app/browser') return
6715
6809
  const roots = browserServerRoots()
@@ -6842,7 +6936,7 @@ ${needsVue ? ` configureServer(server) {
6842
6936
  }
6843
6937
  }
6844
6938
  return null
6845
- },
6939
+ },${needsOutput ? `
6846
6940
  async generateBundle(_options, bundle) {
6847
6941
  for (const output of Object.values(bundle)) {
6848
6942
  if (output.type === 'chunk') {
@@ -6872,7 +6966,7 @@ ${needsVue ? ` configureServer(server) {
6872
6966
  if (pathError !== undefined) this.error(pathError)
6873
6967
  }
6874
6968
  }
6875
- },
6969
+ },` : ""}
6876
6970
  buildEnd(error) {
6877
6971
  if (error !== undefined) return
6878
6972
  for (const id of this.getModuleIds()) {
@@ -6893,16 +6987,10 @@ ${needsVue ? ` configureServer(server) {
6893
6987
  }
6894
6988
  }
6895
6989
  `;
6896
- return `import type {
6897
- CSSOptions,
6898
- HtmlAssetSource,
6899
- HTMLOptions,
6900
- Plugin,
6901
- ResolvedConfig,
6902
- UserConfig,
6903
- } from 'vite'
6904
- import { isCSSRequest, parseAst, preprocessCSS, transformWithOxc, Visitor } from 'vite'
6905
- import { defineConfig, mergeConfig } from 'vitest/config'
6990
+ return `${viteTypeImports}
6991
+ ${needsBrowser ? `import { isCSSRequest, parseSync, preprocessCSS, transformWithOxc, Visitor } from 'vite'
6992
+ ` : `import { parseSync, transformWithOxc, Visitor } from 'vite'
6993
+ `}import { defineConfig, mergeConfig } from 'vitest/config'
6906
6994
  import tsconfig from './tsconfig.json' with { type: 'json' }
6907
6995
  import { fileURLToPath, URL } from 'node:url'
6908
6996
  import { isBuiltin } from 'node:module'
@@ -6917,8 +7005,7 @@ import {
6917
7005
  realpathSync,
6918
7006
  } from 'node:fs'
6919
7007
  import { dirname, isAbsolute, relative, resolve as resolvePath, sep } from 'node:path'
6920
- ${playwrightImports}${vueImports}
6921
- ${needsPlaywright ? `${CONST_KEYWORD} hasChromium = existsSync(chromium.executablePath())\n` : ""}
7008
+ ${playwrightImports}${vueImports}${needsBrowser ? `\n${CONST_KEYWORD} hasChromium = existsSync(chromium.executablePath())\n` : ""}
6922
7009
  ${EXPORT_KEYWORD} function resolveWorkspacePath(relativePath: string): string {
6923
7010
  return fileURLToPath(new URL(relativePath, import.meta.url))
6924
7011
  }
@@ -6939,7 +7026,7 @@ ${CONST_KEYWORD} resolve = {
6939
7026
  }, {}),
6940
7027
  }
6941
7028
 
6942
- ${EXPORT_KEYWORD} ${CONST_KEYWORD} ENVIRONMENT_CSS = Object.freeze({
7029
+ ${needsBrowser ? `${EXPORT_KEYWORD} ${CONST_KEYWORD} ENVIRONMENT_CSS = Object.freeze({
6943
7030
  transformer: 'lightningcss',
6944
7031
  lightningcss: {
6945
7032
  visitor: () => {
@@ -6970,7 +7057,7 @@ ${EXPORT_KEYWORD} ${CONST_KEYWORD} ENVIRONMENT_CSS = Object.freeze({
6970
7057
  },
6971
7058
  },
6972
7059
  } satisfies CSSOptions)
6973
- ${EXPORT_KEYWORD} ${CONST_KEYWORD} PACKAGE_MANIFEST_BYTES = 1_048_576
7060
+ ` : ""}${EXPORT_KEYWORD} ${CONST_KEYWORD} PACKAGE_MANIFEST_BYTES = 1_048_576
6974
7061
  ${EXPORT_KEYWORD} ${CONST_KEYWORD} ENVIRONMENT_MODULE_BYTES = 8_388_608
6975
7062
  ${environmentBoundary}`;
6976
7063
  }
@@ -7007,7 +7094,8 @@ function policyViteProject() {
7007
7094
  * ```
7008
7095
  */
7009
7096
  function singleSrcViteConfig(environment) {
7010
- const header = viteHeader(environment === "browser");
7097
+ const machinery = viteMachinery([environment]);
7098
+ const header = viteHeader(machinery);
7011
7099
  if (environment === "browser") return `${header}
7012
7100
  ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7013
7101
  mergeConfig(
@@ -7015,10 +7103,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7015
7103
  resolve,
7016
7104
  css: ENVIRONMENT_CSS,
7017
7105
  publicDir: false,
7018
- plugins: [
7019
- outputBoundary('dist/src/browser'),
7020
- environmentBoundary('src/browser'),
7021
- ],
7106
+ plugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],
7022
7107
  build: {
7023
7108
  assetsInlineLimit: 0,
7024
7109
  emptyOutDir: true,
@@ -7078,13 +7163,9 @@ export default defineConfig({
7078
7163
  ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
7079
7164
  mergeConfig(
7080
7165
  {
7081
- resolve,
7082
- css: ENVIRONMENT_CSS,
7166
+ resolve,${machinery.browser ? "\n css: ENVIRONMENT_CSS," : ""}
7083
7167
  publicDir: false,
7084
- plugins: [
7085
- outputBoundary('dist/src/server'),
7086
- environmentBoundary('src/server'),
7087
- ],
7168
+ plugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],
7088
7169
  build: {
7089
7170
  emptyOutDir: true,
7090
7171
  sourcemap: true,
@@ -7166,7 +7247,8 @@ export default defineConfig({
7166
7247
  function rootViteConfig(src, engine = false) {
7167
7248
  const hasCore = src.includes("core");
7168
7249
  const nonCore = src.filter((environment) => environment !== "core");
7169
- const header = viteHeader(src.includes("browser"));
7250
+ const machinery = viteMachinery(src);
7251
+ const header = viteHeader(machinery);
7170
7252
  if (!hasCore) {
7171
7253
  const [onlyEnvironment] = nonCore;
7172
7254
  if (onlyEnvironment === "browser" || onlyEnvironment === "server") return singleSrcViteConfig(onlyEnvironment);
@@ -7178,10 +7260,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7178
7260
  {
7179
7261
  css: ENVIRONMENT_CSS,
7180
7262
  publicDir: false,
7181
- plugins: [
7182
- outputBoundary('dist/src/browser'),
7183
- environmentBoundary('src/browser'),
7184
- ],
7263
+ plugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],
7185
7264
  build: {
7186
7265
  assetsInlineLimit: 0,
7187
7266
  lib: {
@@ -7217,13 +7296,9 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7217
7296
  ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
7218
7297
  srcCore(
7219
7298
  mergeConfig(
7220
- {
7221
- css: ENVIRONMENT_CSS,
7299
+ {${machinery.browser ? "\n css: ENVIRONMENT_CSS," : ""}
7222
7300
  publicDir: false,
7223
- plugins: [
7224
- outputBoundary('dist/src/server'),
7225
- environmentBoundary('src/server'),
7226
- ],
7301
+ plugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],
7227
7302
  build: {
7228
7303
  lib: {
7229
7304
  entry: resolveWorkspacePath('src/server/index.ts'),
@@ -7373,7 +7448,8 @@ export default defineConfig({
7373
7448
  */
7374
7449
  function applicationViteConfig(src, app, engine = false) {
7375
7450
  const hasSourceCore = src.includes("core");
7376
- const header = viteHeader(src.includes("browser") || app.includes("browser"), app.includes("browser"));
7451
+ const machinery = viteMachinery(src, app, engine);
7452
+ const header = viteHeader(machinery);
7377
7453
  const projects = [];
7378
7454
  const blocks = [];
7379
7455
  if (src.includes("core")) {
@@ -7382,8 +7458,7 @@ function applicationViteConfig(src, app, engine = false) {
7382
7458
  ${EXPORT_KEYWORD} const srcCore = (config?: UserConfig): UserConfig =>
7383
7459
  mergeConfig(
7384
7460
  {
7385
- resolve,
7386
- css: ENVIRONMENT_CSS,
7461
+ resolve,${machinery.browser ? "\n css: ENVIRONMENT_CSS," : ""}
7387
7462
  publicDir: false,
7388
7463
  plugins: [environmentBoundary('src/core')],
7389
7464
  build: { emptyOutDir: true, sourcemap: true, minify: false },
@@ -7465,8 +7540,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7465
7540
  ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
7466
7541
  mergeConfig(
7467
7542
  {
7468
- resolve,
7469
- css: ENVIRONMENT_CSS,
7543
+ resolve,${machinery.browser ? "\n css: ENVIRONMENT_CSS," : ""}
7470
7544
  publicDir: false,
7471
7545
  plugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],
7472
7546
  build: {
@@ -7502,8 +7576,7 @@ ${EXPORT_KEYWORD} const srcServer = (config?: UserConfig): UserConfig =>
7502
7576
  ${EXPORT_KEYWORD} const appCore = (config?: UserConfig): UserConfig =>
7503
7577
  mergeConfig(
7504
7578
  {
7505
- resolve,
7506
- css: ENVIRONMENT_CSS,
7579
+ resolve,${machinery.browser ? "\n css: ENVIRONMENT_CSS," : ""}
7507
7580
  publicDir: false,
7508
7581
  plugins: [environmentBoundary('app/core')],
7509
7582
  test: {
@@ -7580,8 +7653,7 @@ ${EXPORT_KEYWORD} function appBrowser(...config: readonly never[]): UserConfig {
7580
7653
  ${EXPORT_KEYWORD} const appServer = (config?: UserConfig): UserConfig =>
7581
7654
  mergeConfig(
7582
7655
  {
7583
- resolve,
7584
- css: ENVIRONMENT_CSS,
7656
+ resolve,${machinery.browser ? "\n css: ENVIRONMENT_CSS," : ""}
7585
7657
  publicDir: false,
7586
7658
  plugins: [outputBoundary('dist/app/server'), environmentBoundary('app/server')],
7587
7659
  build: {
@@ -7713,6 +7785,7 @@ function coreTsconfig() {
7713
7785
  * `configs/src/vite.core.config.ts` — inlines its own `build.lib` /
7714
7786
  * `rolldownOptions` (core's `srcCore` root export carries no build.lib).
7715
7787
  *
7788
+ * @param browser - Whether a declared browser environment enables the shared CSS pipeline.
7716
7789
  * @returns The core environment `vite.config.ts` file content, newline-terminated.
7717
7790
  *
7718
7791
  * @example
@@ -7720,12 +7793,11 @@ function coreTsconfig() {
7720
7793
  * coreViteConfig().includes('srcCore(') // true
7721
7794
  * ```
7722
7795
  */
7723
- function coreViteConfig() {
7796
+ function coreViteConfig(browser = true) {
7724
7797
  return `import { defineConfig } from 'vite'
7725
7798
  import dts from 'vite-plugin-dts'
7726
7799
  import {
7727
- ENVIRONMENT_CSS,
7728
- environmentBoundary,
7800
+ ${browser ? " ENVIRONMENT_CSS,\n" : ""} environmentBoundary,
7729
7801
  outputBoundary,
7730
7802
  srcCore,
7731
7803
  resolveWorkspacePath,
@@ -7733,8 +7805,7 @@ import {
7733
7805
 
7734
7806
  export default defineConfig(
7735
7807
  srcCore({
7736
- css: ENVIRONMENT_CSS,
7737
- publicDir: false,
7808
+ ${browser ? " css: ENVIRONMENT_CSS,\n" : ""} publicDir: false,
7738
7809
  plugins: [
7739
7810
  outputBoundary('dist/src/core'),
7740
7811
  environmentBoundary('src/core'),
@@ -7956,6 +8027,7 @@ ${spec.engine || spec.src.includes("browser") || spec.app.includes("browser") ?
7956
8027
  * ```
7957
8028
  */
7958
8029
  function configArtifacts(spec) {
8030
+ const machinery = viteMachinery(spec.src, spec.app, spec.engine);
7959
8031
  const artifacts = [{
7960
8032
  path: "tsconfig.json",
7961
8033
  group: "configs",
@@ -7971,7 +8043,7 @@ function configArtifacts(spec) {
7971
8043
  const row = SRC_MATRIX[environment];
7972
8044
  for (const path of row.configs) {
7973
8045
  const isTsconfig = path.endsWith(".json");
7974
- const content = environment === "core" ? isTsconfig ? coreTsconfig() : coreViteConfig() : isTsconfig ? srcTsconfig(environment) : srcViteConfig(environment);
8046
+ const content = environment === "core" ? isTsconfig ? coreTsconfig() : coreViteConfig(machinery.browser) : isTsconfig ? srcTsconfig(environment) : srcViteConfig(environment);
7975
8047
  artifacts.push({
7976
8048
  path,
7977
8049
  group: "configs",
@@ -9280,5 +9352,6 @@ exports.validateBlueprint = validateBlueprint;
9280
9352
  exports.validateDependencyArray = validateDependencyArray;
9281
9353
  exports.validatePlan = validatePlan;
9282
9354
  exports.viteHeader = viteHeader;
9355
+ exports.viteMachinery = viteMachinery;
9283
9356
 
9284
9357
  //# sourceMappingURL=index.cjs.map