@orkestrel/scaffold 0.0.16 → 0.0.17

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.
@@ -1177,7 +1177,7 @@ export declare function coreViteConfig(): string;
1177
1177
  readonly content: string;
1178
1178
  readonly freshness: Freshness;
1179
1179
  readonly note?: string;
1180
- /** SHA-256 of the observed local mirror, or `absent`; omitted outside target-aware pulls. */
1180
+ /** SHA-256 of the observed local mirror, or `absent`; omitted outside target-aware synchronization. */
1181
1181
  readonly baseline?: string;
1182
1182
  }
1183
1183
 
@@ -2275,7 +2275,7 @@ export declare function coreViteConfig(): string;
2275
2275
  export declare function rootViteConfig(src: readonly Environment[], facts?: ViteFacts): string;
2276
2276
 
2277
2277
  /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
2278
- export declare const SCAFFOLD_RANGE = "^0.0.16";
2278
+ export declare const SCAFFOLD_RANGE = "^0.0.17";
2279
2279
 
2280
2280
  /**
2281
2281
  * Carries a `ScaffoldErrorCode` + optional `context` (AGENTS §12).
@@ -2537,7 +2537,7 @@ export declare function coreViteConfig(): string;
2537
2537
  export declare const SYNC_BASELINE_PATTERN: RegExp;
2538
2538
 
2539
2539
  /**
2540
- * The whole outcome of a `Sync.pull`.
2540
+ * The whole outcome of a `Sync.pull` or `Sync.mirror` synchronization.
2541
2541
  *
2542
2542
  * @remarks
2543
2543
  * `clean` is `true` iff no drift AND no failures; `failed` is the count of
@@ -1177,7 +1177,7 @@ export declare function coreViteConfig(): string;
1177
1177
  readonly content: string;
1178
1178
  readonly freshness: Freshness;
1179
1179
  readonly note?: string;
1180
- /** SHA-256 of the observed local mirror, or `absent`; omitted outside target-aware pulls. */
1180
+ /** SHA-256 of the observed local mirror, or `absent`; omitted outside target-aware synchronization. */
1181
1181
  readonly baseline?: string;
1182
1182
  }
1183
1183
 
@@ -2275,7 +2275,7 @@ export declare function coreViteConfig(): string;
2275
2275
  export declare function rootViteConfig(src: readonly Environment[], facts?: ViteFacts): string;
2276
2276
 
2277
2277
  /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
2278
- export declare const SCAFFOLD_RANGE = "^0.0.16";
2278
+ export declare const SCAFFOLD_RANGE = "^0.0.17";
2279
2279
 
2280
2280
  /**
2281
2281
  * Carries a `ScaffoldErrorCode` + optional `context` (AGENTS §12).
@@ -2537,7 +2537,7 @@ export declare function coreViteConfig(): string;
2537
2537
  export declare const SYNC_BASELINE_PATTERN: RegExp;
2538
2538
 
2539
2539
  /**
2540
- * The whole outcome of a `Sync.pull`.
2540
+ * The whole outcome of a `Sync.pull` or `Sync.mirror` synchronization.
2541
2541
  *
2542
2542
  * @remarks
2543
2543
  * `clean` is `true` iff no drift AND no failures; `failed` is the count of
@@ -226,7 +226,7 @@ var DEFAULT_VERSION = "0.0.1";
226
226
  /** The `engines.node` range the `blueprint` builder fills. */
227
227
  var DEFAULT_ENGINES = `>=${MINIMUM_NODE_VERSION}`;
228
228
  /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
229
- var SCAFFOLD_RANGE = "^0.0.16";
229
+ var SCAFFOLD_RANGE = "^0.0.17";
230
230
  /** Tooling versions shared by scaffold and every generated workspace. */
231
231
  var BASE_DEV_DEPENDENCIES = Object.freeze({
232
232
  "@microsoft/api-extractor": "^7.58.12",
@@ -5872,7 +5872,7 @@ ${renderedProjects}
5872
5872
  ${fitsPrintWidth(inlineRegistrations) ? inlineRegistrations : ` [
5873
5873
  ${renderedRegistrations.map((registration) => ` ${registration},`).join("\n")}
5874
5874
  ],`}
5875
- chromiumPath !== undefined,
5875
+ browserOptions !== undefined,
5876
5876
  process.argv,
5877
5877
  ),`;
5878
5878
  }
@@ -5896,6 +5896,8 @@ ${renderedRegistrations.map((registration) => ` ${registration},`).join("\n")}
5896
5896
  */
5897
5897
  function viteHeader(machinery) {
5898
5898
  const { browser: needsBrowser, vue: needsVue, output: needsOutput } = machinery;
5899
+ const playwrightTypeImports = needsBrowser ? `import type { PlaywrightProviderOptions } from '@vitest/browser-playwright'
5900
+ ` : "";
5899
5901
  const playwrightImports = needsBrowser ? `import { playwright } from '@vitest/browser-playwright'
5900
5902
  import { chromium } from 'playwright'
5901
5903
  ` : "";
@@ -6206,7 +6208,9 @@ import { parse as parseVue } from 'vue/compiler-sfc'
6206
6208
  ? undefined
6207
6209
  : packageRootOf(packageName, physicalSource)
6208
6210
  if (packageRoot === undefined || !containedPath(packageRoot, physicalSource)) {
6209
- this.error('Resolved dependencies must remain inside their physical package root')
6211
+ return this.error(
6212
+ 'Resolved dependencies must remain inside their physical package root',
6213
+ )
6210
6214
  }
6211
6215
  trustedPackageRoots.add(packageRoot)
6212
6216
  }
@@ -6214,7 +6218,7 @@ import { parse as parseVue } from 'vue/compiler-sfc'
6214
6218
  }
6215
6219
  const resolvedSource = workspacePath(physicalSource)
6216
6220
  if (resolvedSource === undefined) {
6217
- this.error('Environment modules cannot import files outside the workspace')
6221
+ return this.error('Environment modules cannot import files outside the workspace')
6218
6222
  }
6219
6223
  const assetError = environmentPathError(owner, resolvedSource)
6220
6224
  if (assetError !== undefined) this.error(assetError)
@@ -7243,7 +7247,7 @@ ${needsVue ? ` configureServer(server) {
7243
7247
  }
7244
7248
  }
7245
7249
  `;
7246
- return `${viteTypeImports}
7250
+ return `${playwrightTypeImports}${viteTypeImports}
7247
7251
  ${needsBrowser ? `import { isCSSRequest, parseSync, preprocessCSS, transformWithOxc, Visitor } from 'vite'
7248
7252
  ` : `import { parseSync, transformWithOxc, Visitor } from 'vite'
7249
7253
  `}import { defineConfig, mergeConfig } from 'vitest/config'
@@ -7251,7 +7255,7 @@ import tsconfig from './tsconfig.json' with { type: 'json' }
7251
7255
  import { fileURLToPath, URL } from 'node:url'
7252
7256
  import { isBuiltin } from 'node:module'
7253
7257
  import {
7254
- closeSync,
7258
+ ${needsBrowser ? " accessSync,\n" : ""} closeSync,
7255
7259
  constants as FS_CONSTANTS,
7256
7260
  existsSync,
7257
7261
  fstatSync,
@@ -7260,7 +7264,15 @@ import {
7260
7264
  ${needsBrowser ? " readdirSync,\n" : ""} readSync,
7261
7265
  realpathSync,
7262
7266
  ${needsBrowser ? " statSync,\n" : ""}} from 'node:fs'
7263
- import { ${needsBrowser ? "basename, " : ""}dirname, isAbsolute, relative, resolve as resolvePath, sep } from 'node:path'
7267
+ ${needsBrowser ? `import {
7268
+ basename,
7269
+ join,
7270
+ dirname,
7271
+ isAbsolute,
7272
+ relative,
7273
+ resolve as resolvePath,
7274
+ sep,
7275
+ } from 'node:path'` : `import { dirname, isAbsolute, relative, resolve as resolvePath, sep } from 'node:path'`}
7264
7276
  ${playwrightImports}${vueImports}${needsBrowser ? `\n/** Chromium executable layouts inside a \`chromium-<revision>\` browsers-directory entry, per platform. */
7265
7277
  ${EXPORT_KEYWORD} ${CONST_KEYWORD} CHROMIUM_LAYOUTS = Object.freeze([
7266
7278
  'chrome-linux/chrome',
@@ -7271,15 +7283,64 @@ ${EXPORT_KEYWORD} ${CONST_KEYWORD} CHROMIUM_LAYOUTS = Object.freeze([
7271
7283
  'chrome-mac-arm64/Chromium.app/Contents/MacOS/Chromium',
7272
7284
  ])
7273
7285
 
7286
+ /** Stable Playwright Chromium channels and their standard executable layouts. */
7287
+ ${EXPORT_KEYWORD} ${CONST_KEYWORD} SYSTEM_BROWSER_CHANNELS = Object.freeze([
7288
+ Object.freeze({
7289
+ channel: 'chrome',
7290
+ layouts: Object.freeze({
7291
+ linux: '/opt/google/chrome/chrome',
7292
+ darwin: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
7293
+ win32: Object.freeze(['Google', 'Chrome', 'Application', 'chrome.exe']),
7294
+ }),
7295
+ }),
7296
+ Object.freeze({
7297
+ channel: 'msedge',
7298
+ layouts: Object.freeze({
7299
+ linux: '/opt/microsoft/msedge/msedge',
7300
+ darwin: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
7301
+ win32: Object.freeze(['Microsoft', 'Edge', 'Application', 'msedge.exe']),
7302
+ }),
7303
+ }),
7304
+ ])
7305
+
7306
+ /**
7307
+ * Determine whether a path identifies an executable regular file.
7308
+ *
7309
+ * @param path - The filesystem path to inspect.
7310
+ * @returns Whether the path is a regular file with execute access.
7311
+ *
7312
+ * @example
7313
+ * \`\`\`ts
7314
+ * isBrowserExecutable('/opt/google/chrome/chrome')
7315
+ * \`\`\`
7316
+ */
7317
+ ${EXPORT_KEYWORD} function isBrowserExecutable(path: string): boolean {
7318
+ try {
7319
+ if (!statSync(path).isFile()) return false
7320
+ accessSync(path, FS_CONSTANTS.X_OK)
7321
+ return true
7322
+ } catch {
7323
+ return false
7324
+ }
7325
+ }
7326
+
7274
7327
  /**
7275
- * Resolve a launchable Chromium executable: the pinned revision when installed,
7328
+ * Resolve a launchable Playwright-managed Chromium executable: the pinned revision when installed,
7276
7329
  * otherwise a \`chromium\` / \`chromium.exe\` alias or any other \`chromium-*\`
7277
7330
  * revision under the same Playwright browsers directory. A pinned-revision miss
7278
7331
  * is not Chromium absence — managed containers ship one usable build (often
7279
7332
  * behind a revision-agnostic alias) for many Playwright versions.
7333
+ *
7334
+ * @param pinned - The executable path for Playwright's pinned Chromium revision.
7335
+ * @returns The managed executable path, or \`undefined\` when none is executable.
7336
+ *
7337
+ * @example
7338
+ * \`\`\`ts
7339
+ * resolveManagedBrowser(chromium.executablePath())
7340
+ * \`\`\`
7280
7341
  */
7281
- ${EXPORT_KEYWORD} function resolveChromium(pinned: string): string | undefined {
7282
- if (existsSync(pinned)) return pinned
7342
+ ${EXPORT_KEYWORD} function resolveManagedBrowser(pinned: string): string | undefined {
7343
+ if (isBrowserExecutable(pinned)) return pinned
7283
7344
  let revisionRoot = dirname(pinned)
7284
7345
  for (;;) {
7285
7346
  if (/^chromium-\\d+$/.test(basename(revisionRoot))) break
@@ -7290,7 +7351,7 @@ ${EXPORT_KEYWORD} function resolveChromium(pinned: string): string | undefined {
7290
7351
  const browsersRoot = dirname(revisionRoot)
7291
7352
  for (const alias of ['chromium', 'chromium.exe']) {
7292
7353
  const candidate = resolvePath(browsersRoot, alias)
7293
- if (existsSync(candidate) && statSync(candidate).isFile()) return candidate
7354
+ if (isBrowserExecutable(candidate)) return candidate
7294
7355
  }
7295
7356
  let entries: readonly string[]
7296
7357
  try {
@@ -7304,18 +7365,89 @@ ${EXPORT_KEYWORD} function resolveChromium(pinned: string): string | undefined {
7304
7365
  for (const revision of revisions) {
7305
7366
  for (const layout of CHROMIUM_LAYOUTS) {
7306
7367
  const candidate = resolvePath(browsersRoot, revision, layout)
7307
- if (existsSync(candidate)) return candidate
7368
+ if (isBrowserExecutable(candidate)) return candidate
7369
+ }
7370
+ }
7371
+ return undefined
7372
+ }
7373
+
7374
+ /**
7375
+ * Resolve the first installed stable system Chromium channel.
7376
+ *
7377
+ * @param platform - The Node platform whose standard layouts should be probed.
7378
+ * @param environment - The process environment supplying Windows installation roots.
7379
+ * @returns \`chrome\`, then \`msedge\`, or \`undefined\` when neither is executable.
7380
+ *
7381
+ * @example
7382
+ * \`\`\`ts
7383
+ * resolveSystemBrowser(process.platform, process.env)
7384
+ * \`\`\`
7385
+ */
7386
+ ${EXPORT_KEYWORD} function resolveSystemBrowser(
7387
+ platform: NodeJS.Platform,
7388
+ environment: NodeJS.ProcessEnv,
7389
+ ): string | undefined {
7390
+ if (platform !== 'linux' && platform !== 'darwin' && platform !== 'win32') return undefined
7391
+ const roots = new Set<string>()
7392
+ if (platform === 'win32') {
7393
+ for (const root of [
7394
+ environment.LOCALAPPDATA,
7395
+ environment.PROGRAMFILES,
7396
+ environment['PROGRAMFILES(X86)'],
7397
+ ]) {
7398
+ if (root !== undefined && root.length > 0) roots.add(root)
7399
+ }
7400
+ const homeDrive = environment.HOMEDRIVE
7401
+ if (homeDrive !== undefined && homeDrive.length > 0) {
7402
+ roots.add(join(homeDrive, 'Program Files'))
7403
+ roots.add(join(homeDrive, 'Program Files (x86)'))
7404
+ }
7405
+ }
7406
+ for (const browser of SYSTEM_BROWSER_CHANNELS) {
7407
+ if (platform === 'win32') {
7408
+ for (const root of roots) {
7409
+ if (isBrowserExecutable(join(root, ...browser.layouts.win32))) return browser.channel
7410
+ }
7411
+ continue
7308
7412
  }
7413
+ if (isBrowserExecutable(browser.layouts[platform])) return browser.channel
7309
7414
  }
7310
7415
  return undefined
7311
7416
  }
7312
7417
 
7313
- ${CONST_KEYWORD} chromiumPinned = chromium.executablePath()
7314
- ${CONST_KEYWORD} chromiumPath = resolveChromium(chromiumPinned)
7315
- ${CONST_KEYWORD} chromiumOptions =
7316
- chromiumPath === undefined || chromiumPath === chromiumPinned
7317
- ? {}
7318
- : { launchOptions: { executablePath: chromiumPath } }
7418
+ /**
7419
+ * Resolve launch options for a managed Chromium or stable system browser.
7420
+ *
7421
+ * @param pinned - The executable path for Playwright's pinned Chromium revision.
7422
+ * @param platform - The Node platform whose standard system layouts should be probed.
7423
+ * @param environment - The process environment supplying Windows installation roots.
7424
+ * @returns Provider options for managed Chromium, Chrome, or Edge, or \`undefined\`.
7425
+ *
7426
+ * @remarks
7427
+ * An installed pinned revision returns an empty object so Playwright retains
7428
+ * its default launch semantics. A different managed executable is selected by
7429
+ * path; a system browser is selected by its stable Playwright channel.
7430
+ *
7431
+ * @example
7432
+ * \`\`\`ts
7433
+ * resolveBrowser(chromium.executablePath(), process.platform, process.env)
7434
+ * \`\`\`
7435
+ */
7436
+ ${EXPORT_KEYWORD} function resolveBrowser(
7437
+ pinned: string,
7438
+ platform: NodeJS.Platform,
7439
+ environment: NodeJS.ProcessEnv,
7440
+ ): PlaywrightProviderOptions | undefined {
7441
+ const managed = resolveManagedBrowser(pinned)
7442
+ if (managed !== undefined) {
7443
+ return managed === pinned ? {} : { launchOptions: { executablePath: managed } }
7444
+ }
7445
+ const channel = resolveSystemBrowser(platform, environment)
7446
+ return channel === undefined ? undefined : { launchOptions: { channel } }
7447
+ }
7448
+
7449
+ ${CONST_KEYWORD} browserPinned = chromium.executablePath()
7450
+ ${CONST_KEYWORD} browserOptions = resolveBrowser(browserPinned, process.platform, process.env)
7319
7451
  ` : ""}
7320
7452
  ${EXPORT_KEYWORD} function resolveWorkspacePath(relativePath: string): string {
7321
7453
  return fileURLToPath(new URL(relativePath, import.meta.url))
@@ -7364,7 +7496,9 @@ ${needsBrowser ? `${EXPORT_KEYWORD} function gateBrowserProjects(
7364
7496
  projects.push(registration.project())
7365
7497
  }
7366
7498
  if (gated.length === 0) return { projects }
7367
- console.warn(\`browser projects skipped: Chromium absent (\${gated.join(', ')})\`)
7499
+ console.warn(
7500
+ \`browser projects skipped: no Playwright Chromium, Chrome, or Edge found (\${gated.join(', ')})\`,
7501
+ )
7368
7502
  const filters: string[] = []
7369
7503
  let readable = true
7370
7504
  for (let index = 0; index < argv.length; index += 1) {
@@ -7655,7 +7789,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7655
7789
  }),
7656
7790
  browser: {
7657
7791
  enabled: true,
7658
- provider: playwright(chromiumOptions),
7792
+ provider: playwright(browserOptions),
7659
7793
  instances: [{ browser: 'chromium', headless: true }],
7660
7794
  },
7661
7795
  fileParallelism: false,
@@ -7787,7 +7921,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7787
7921
  }),
7788
7922
  browser: {
7789
7923
  enabled: true,
7790
- provider: playwright(chromiumOptions),
7924
+ provider: playwright(browserOptions),
7791
7925
  instances: [{ browser: 'chromium', headless: true }],
7792
7926
  },
7793
7927
  fileParallelism: false,
@@ -7952,7 +8086,7 @@ ${EXPORT_KEYWORD} const srcBrowser = (config?: UserConfig): UserConfig =>
7952
8086
  }),
7953
8087
  browser: {
7954
8088
  enabled: true,
7955
- provider: playwright(chromiumOptions),
8089
+ provider: playwright(browserOptions),
7956
8090
  instances: [{ browser: 'chromium', headless: true }],
7957
8091
  },
7958
8092
  fileParallelism: false,
@@ -8081,7 +8215,7 @@ ${EXPORT_KEYWORD} function appBrowser(...config: readonly never[]): UserConfig {
8081
8215
  },
8082
8216
  browser: {
8083
8217
  enabled: true,
8084
- provider: playwright(chromiumOptions),
8218
+ provider: playwright(browserOptions),
8085
8219
  instances: [{ browser: 'chromium', headless: true }],
8086
8220
  },
8087
8221
  fileParallelism: false,
@@ -8648,8 +8782,7 @@ function paritySpecifiers(spec) {
8648
8782
  function testArtifacts(spec, pascal) {
8649
8783
  const hasBrowser = spec.src.includes("browser") || spec.app.includes("browser");
8650
8784
  const hasVue = spec.app.includes("browser");
8651
- const browserPolicySpecifier = hasBrowser ? ", accessSync, constants as FS_CONSTANTS, statSync" : "";
8652
- const browserPolicyImport = hasBrowser ? "\nimport { chromium } from 'playwright'\nimport { resolveChromium } from '../vite.config.js'" : "";
8785
+ const browserPolicyImport = hasBrowser ? "\nimport { chromium } from 'playwright'\nimport { isBrowserExecutable, resolveBrowser, SYSTEM_BROWSER_CHANNELS } from '../vite.config.js'" : "";
8653
8786
  const vuePolicyImport = hasVue ? "\nimport { parse as parseVue } from 'vue/compiler-sfc'" : "";
8654
8787
  const workspacePolicyAssertion = hasVue ? `expect(
8655
8788
  inspectCodingWorkspace(process.cwd(), (path, content) => {
@@ -8662,15 +8795,20 @@ function testArtifacts(spec, pascal) {
8662
8795
  ).toEqual([])` : "expect(inspectCodingWorkspace(process.cwd())).toEqual([])";
8663
8796
  const browserPolicyTest = hasBrowser ? `
8664
8797
 
8665
- it('resolves Chromium only to a real executable file', () => {
8666
- const chromiumPath = resolveChromium(chromium.executablePath())
8667
- if (chromiumPath === undefined) return
8668
-
8669
- expect(statSync(chromiumPath).isFile()).toBe(true)
8670
- expect(() => accessSync(chromiumPath, FS_CONSTANTS.X_OK)).not.toThrow()
8798
+ it('resolves only a real managed executable or stable system browser channel', () => {
8799
+ const options = resolveBrowser(chromium.executablePath(), process.platform, process.env)
8800
+ let valid = options === undefined
8801
+ if (options !== undefined) {
8802
+ const channel = options.launchOptions?.channel
8803
+ valid =
8804
+ channel === undefined
8805
+ ? isBrowserExecutable(options.launchOptions?.executablePath ?? chromium.executablePath())
8806
+ : SYSTEM_BROWSER_CHANNELS.some((browser) => browser.channel === channel)
8807
+ }
8808
+ expect(valid).toBe(true)
8671
8809
  })` : "";
8672
8810
  const artifacts = [fillArtifact("tests/setup.ts", "tests", "setup", {}), fillArtifact("tests/policy.test.ts", "tests", "policyTest", {
8673
- browserPolicySpecifier,
8811
+ browserPolicySpecifier: "",
8674
8812
  browserPolicyImport,
8675
8813
  browserPolicyTest,
8676
8814
  vuePolicyImport,