@orkestrel/scaffold 0.0.30 → 0.0.32

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.
@@ -95,7 +95,7 @@ export declare const ARTIFACT_TEMPLATES: Readonly<{
95
95
  global: "export function setup(): void {}\n";
96
96
  entry: "import * as entry from {{specifier}}\nimport { describe, expect, it } from 'vitest'\n\ndescribe({{label}}, () => {\n\tit('has no starter exports', () => {\n\t\texpect(Object.keys(entry)).toStrictEqual([])\n\t})\n})\n";
97
97
  bin: "import { describe, expect, it } from 'vitest'\n\ndescribe('bin entry', () => {\n\tit('has no starter exports', async () => {\n{{import}}\n\t\texpect(Object.keys(entry)).toStrictEqual([])\n\t})\n})\n";
98
- integration: "import { spawnSync } from 'node:child_process'\nimport { globSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { describe, expect, it } from 'vitest'\n\nconst root = resolve(dirname(fileURLToPath(import.meta.url)), '..')\nconst npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'\nconst registry =\n\tspawnSync(npm, ['ping', '--fetch-retries=0', '--fetch-timeout=1000', '--loglevel=silent'], {\n\t\tcwd: root,\n\t\tstdio: 'ignore',\n\t\ttimeout: 5_000,\n\t\twindowsHide: true,\n\t}).status === 0\n\ndescribe('installed package consumer', () => {\n\tit('loads the built package from a process outside the workspace', () => {\n\t\tconst workspace = mkdtempSync(join(tmpdir(), 'orkestrel-integration-driver-'))\n\t\ttry {\n\t\t\tconst manifest: unknown = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'))\n\t\t\tif (typeof manifest !== 'object' || manifest === null) {\n\t\t\t\tthrow new Error('The package manifest is not a record')\n\t\t\t}\n\t\t\tconst module: unknown = Object.getOwnPropertyDescriptor(manifest, 'module')?.value\n\t\t\tif (typeof module !== 'string')\n\t\t\t\tthrow new Error('The package manifest carries no module entry')\n\t\t\tconst entry = pathToFileURL(resolve(root, module)).href\n\t\t\tconst missing = pathToFileURL(resolve(root, 'dist/outside-integration-control.js')).href\n\t\t\tconst control = spawnSync(\n\t\t\t\tprocess.execPath,\n\t\t\t\t['--input-type=module', '--eval', 'await import(' + JSON.stringify(missing) + ')'],\n\t\t\t\t{ cwd: workspace, encoding: 'utf8', windowsHide: true },\n\t\t\t)\n\t\t\texpect(control.status).not.toBe(0)\n\t\t\tconst driven = spawnSync(\n\t\t\t\tprocess.execPath,\n\t\t\t\t['--input-type=module', '--eval', 'await import(' + JSON.stringify(entry) + ')'],\n\t\t\t\t{ cwd: workspace, encoding: 'utf8', windowsHide: true },\n\t\t\t)\n\t\t\texpect(driven.status).toBe(0)\n\t\t\texpect(driven.stderr).toBe('')\n\t\t} finally {\n\t\t\trmSync(workspace, { recursive: true, force: true })\n\t\t}\n\t})\n\n\tit.skipIf(!registry)(\n\t\t'installs the packed package into an outside consumer [requires a reachable npm registry]',\n\t\t() => {\n\t\t\tconst workspace = mkdtempSync(join(tmpdir(), 'orkestrel-integration-install-'))\n\t\t\tconst packed = join(workspace, 'packed')\n\t\t\tconst consumer = join(workspace, 'consumer')\n\t\t\ttry {\n\t\t\t\tmkdirSync(packed, { recursive: true })\n\t\t\t\tmkdirSync(consumer, { recursive: true })\n\t\t\t\tconst pack = spawnSync(\n\t\t\t\t\tnpm,\n\t\t\t\t\t['pack', '--json', '--ignore-scripts', '--pack-destination', packed],\n\t\t\t\t\t{ cwd: root, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(pack.status).toBe(0)\n\t\t\t\tconst archives = globSync('*.tgz', { cwd: packed })\n\t\t\t\texpect(archives).toHaveLength(1)\n\t\t\t\tconst archive = archives[0]\n\t\t\t\tif (archive === undefined) throw new Error('The package archive was not written')\n\t\t\t\twriteFileSync(\n\t\t\t\t\tjoin(consumer, 'package.json'),\n\t\t\t\t\t'{\"name\":\"outside-consumer\",\"private\":true,\"type\":\"module\"}\\n',\n\t\t\t\t)\n\t\t\t\tconst install = spawnSync(\n\t\t\t\t\tnpm,\n\t\t\t\t\t['install', '--ignore-scripts', '--no-audit', '--no-fund', join(packed, archive)],\n\t\t\t\t\t{ cwd: consumer, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(install.status).toBe(0)\n\t\t\t\tconst manifest: unknown = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'))\n\t\t\t\tif (typeof manifest !== 'object' || manifest === null) {\n\t\t\t\t\tthrow new Error('The package manifest is not a record')\n\t\t\t\t}\n\t\t\t\tconst name: unknown = Object.getOwnPropertyDescriptor(manifest, 'name')?.value\n\t\t\t\tif (typeof name !== 'string') throw new Error('The package manifest carries no name')\n\t\t\t\tconst control = spawnSync(\n\t\t\t\t\tprocess.execPath,\n\t\t\t\t\t[\n\t\t\t\t\t\t'--input-type=module',\n\t\t\t\t\t\t'--eval',\n\t\t\t\t\t\t'await import(' + JSON.stringify(name + '/outside-integration-control') + ')',\n\t\t\t\t\t],\n\t\t\t\t\t{ cwd: consumer, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(control.status).not.toBe(0)\n\t\t\t\tconst driven = spawnSync(\n\t\t\t\t\tprocess.execPath,\n\t\t\t\t\t['--input-type=module', '--eval', 'await import(' + JSON.stringify(name) + ')'],\n\t\t\t\t\t{ cwd: consumer, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(driven.status).toBe(0)\n\t\t\t\texpect(driven.stderr).toBe('')\n\t\t\t} finally {\n\t\t\t\trmSync(workspace, { recursive: true, force: true })\n\t\t\t}\n\t\t},\n\t\t300_000,\n\t)\n})\n";
98
+ integration: "{{imports}}import { describe, expect, it } from 'vitest'\n\ndescribe('workspace integration', () => {\n\tit('loads every selected public barrel together as a composition seed', () => {\n\t\t// Replace this empty-barrel seed with one observable flow that passes one\n\t\t// environment's public result into another.\n\t\t{{actual}}{{expected}})\n\t})\n})\n";
99
99
  }>;
100
100
  docs: Readonly<{
101
101
  readme: "# {{package}}\n\n{{description}}\n\n## Development\n\n```sh\nnpm install\nnpm test\n```\n";
@@ -235,15 +235,14 @@ export declare const BIN_ENTRY_PATH = "src/bin/main.ts";
235
235
  * application-only, and mixed workspaces are all first class. `dependencies`
236
236
  * and `peers` are runtime `@orkestrel/*` packages; `extras` are
237
237
  * package-specific development dependencies and may carry any valid npm name.
238
- * `bin`, `integration`, `conformance`, `service`, `vendors`, `global`, and
239
- * `showcase` are structural facts: each is set only when the workspace
240
- * physically ships the directory or exact-case file that defines it, never
241
- * because of the workspace's name and never because a sibling fact is set. An
242
- * axis-dependent fact projects nothing when its required axis is absent:
243
- * `integration` projects only a published `src`, and `showcase` projects only a
244
- * browser `app`. The gate answers that case with a non-blocking question, so a
245
- * caller that set the flag learns it emitted nothing and the compile still
246
- * completes.
238
+ * `bin`, `guides`, `distribution`, `integration`, `conformance`, `service`,
239
+ * `vendors`, `global`, and `showcase` are structural facts: each is set only
240
+ * when the workspace physically ships the directory or exact-case file that
241
+ * defines it, never because of the workspace's name and never because a sibling
242
+ * fact is set.
243
+ * `showcase` projects only a browser `app`. The gate answers an absent browser
244
+ * axis with a non-blocking question, so a caller that set the flag learns it
245
+ * emitted nothing and the compile still completes.
247
246
  *
248
247
  * `service` says the workspace runs a live-service Vitest project over
249
248
  * `tests/service`, and it alone registers that project. `vendors` names each
@@ -265,6 +264,8 @@ export declare interface Blueprint {
265
264
  readonly engines: string;
266
265
  readonly overrides: readonly Override[];
267
266
  readonly bin: boolean;
267
+ readonly guides: boolean;
268
+ readonly distribution: boolean;
268
269
  readonly integration: boolean;
269
270
  readonly conformance: boolean;
270
271
  readonly service: boolean;
@@ -438,12 +439,19 @@ export declare function blueprintToOrchestrationArtifacts(blueprint: Blueprint):
438
439
  *
439
440
  * A question blocks when it describes a workspace this package cannot generate.
440
441
  * Three do not, because each describes a workspace it can describe honestly and
441
- * should not create: a published axis of several environments without core, whose
442
- * manifest names a core build the workspace never runs, and a structural flag
443
- * whose required axis is absent, which emits nothing. Blocking those closed the
444
- * gate for every verb, and the verbs that read an existing workspace need the
445
- * plan the gate refused. The caller that chooses the shape refuses the advisory;
446
- * the callers that read one report it.
442
+ * should not create: a published axis of several environments without core,
443
+ * whose manifest names a core build the workspace never runs; a showcase flag
444
+ * whose required browser axis is absent, which emits nothing; and an
445
+ * integration flag over fewer than two environments, whose seed does emit and
446
+ * has nothing to compose across. Blocking any of them closed the gate for every
447
+ * verb. The verbs that read an existing workspace need the plan the gate
448
+ * refused. The caller that chooses the shape refuses the advisory; the callers
449
+ * that read one report it.
450
+ *
451
+ * The integration advisory counts both axes together, because the proof it
452
+ * seeds spans environments rather than published ones: an application of two
453
+ * environments composes, and a package publishing one does not. Reading either
454
+ * axis alone withdrew the proof from a workspace that does compose.
447
455
  *
448
456
  * An environment question carries `ENVIRONMENTS` as its candidates, so a caller
449
457
  * reads the accepted values from the question instead of from the documentation.
@@ -511,12 +519,13 @@ export declare function blueprintToRootVite(blueprint: Blueprint): string;
511
519
  * proofs every workspace can pass before it has a public API, and one build per
512
520
  * target that actually builds.
513
521
  *
514
- * A proof leaves `test` when a real service or a real install answers it. The
515
- * installed-package integration proof and the live-service proof therefore run
516
- * from `prepublishOnly` instead. The conformance proof stays in `test`, because
517
- * it measures this package against official tooling and drives nothing external:
518
- * a conformance run may start a server, but it starts its own and reaches it
519
- * over loopback, so the run stays hermetic.
522
+ * A publishing workspace isolates distribution and live-service proofs from
523
+ * `test` and runs them from `prepublishOnly` instead. A private workspace has
524
+ * no publish lifecycle, so it omits distribution and runs a live-service proof
525
+ * from `test`. Integration and conformance stay in `test` because they neither
526
+ * pack nor install the workspace and drive no external service. A conformance
527
+ * run may start a server, but it starts its own and reaches it over loopback,
528
+ * so the run stays hermetic.
520
529
  *
521
530
  * The configuration paths interpolated here are the same ones `SRC_MATRIX` and
522
531
  * `APP_MATRIX` list as each environment's configuration files, so a rename in
@@ -562,15 +571,14 @@ export declare function blueprintToSourceArtifacts(blueprint: Blueprint): readon
562
571
  * Compile every artifact in the `tests` group that is not vendored from the host.
563
572
  *
564
573
  * @param blueprint - The workspace specification.
565
- * @returns Shared setup modules, axis tests, and the optional install proof.
574
+ * @returns Shared setup modules, axis tests, and the optional integration seed.
566
575
  *
567
576
  * @remarks
568
577
  * `tests/setupPolicy.ts`, `tests/policy.test.ts`, and `tests/config.test.ts` are
569
578
  * fleet-invariant host artifacts and therefore do not appear here. A guide
570
579
  * proof is not emitted while the workspace intentionally has empty barrels and
571
- * no package guide. The install proof is meaningful only for a published
572
- * workspace and therefore follows the `src` axis as well as its structural
573
- * flag.
580
+ * no package guide. The integration seed follows its structural flag and loads
581
+ * every selected environment through its public barrel.
574
582
  *
575
583
  * The conformance proof is not emitted either, for the reason the guide proof
576
584
  * is not: it names an official artifact only the package knows, so a generated
@@ -1026,18 +1034,18 @@ export declare class Compiler implements CompilerInterface {
1026
1034
  export declare const CONFIG_TEMPLATES: Readonly<{
1027
1035
  root: Readonly<{
1028
1036
  tsconfig: "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"ESNext\",\n\t\t\"module\": \"ESNext\",\n\t\t\"moduleResolution\": \"bundler\",\n\t\t\"allowImportingTsExtensions\": true,\n\t\t\"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n\t\t\"types\": [\"node\", \"vite/client\", \"vitest/globals\"],\n\t\t\"moduleDetection\": \"force\",\n\t\t\"resolveJsonModule\": true,\n\t\t\"strict\": true,\n\t\t\"verbatimModuleSyntax\": true,\n\t\t\"noUncheckedIndexedAccess\": true,\n\t\t\"noUncheckedSideEffectImports\": true,\n\t\t\"exactOptionalPropertyTypes\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"noUnusedParameters\": true,\n\t\t\"noImplicitOverride\": true,\n\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"noEmit\": true,\n\t\t\"paths\": {\n{{paths}}\n\t\t}\n\t},\n\t\"exclude\": [\"node_modules\", \"dist\", \"tmp\"]\n}\n";
1029
- vite: "import type { {{viteTypes}} } from 'vite'\n{{imports}}import { defineConfig, mergeConfig } from 'vitest/config'\nimport tsconfig from './tsconfig.json' with { type: 'json' }\n{{helpers}}{{browsers}}import { lstatSync, readdirSync, realpathSync } from 'node:fs'\nimport { basename, join, parse, relative, resolve as resolvePath, sep } from 'node:path'\nimport { fileURLToPath, URL } from 'node:url'\n\n{{options}}export function resolveWorkspacePath(relativePath: string): string {\n\treturn fileURLToPath(new URL(relativePath, import.meta.url))\n}\n\n// A generated root config must classify its own fixed proof without importing\n// package source, so the exact-case check stays self-contained over Node APIs.\nfunction isExactCaseFile(path: string): boolean {\n\tconst full = resolvePath(path)\n\ttry {\n\t\tconst status = lstatSync(full)\n\t\tif (!status.isFile() || status.isSymbolicLink() || status.nlink !== 1) return false\n\t\tconst root = parse(full).root\n\t\tconst segments = relative(root, full).split(sep)\n\t\tlet parent = root\n\t\tfor (const segment of segments) {\n\t\t\ttry {\n\t\t\t\tif (!readdirSync(parent).includes(segment)) return false\n\t\t\t} catch {\n\t\t\t\tif (basename(realpathSync.native(join(parent, segment))) !== segment) return false\n\t\t\t}\n\t\t\tparent = join(parent, segment)\n\t\t}\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nconst resolve = {\n\talias: Object.entries(tsconfig.compilerOptions.paths).reduce((aliases, [key, values]) => {\n\t\tconst [path] = values\n\t\tif (path === undefined) throw new Error('tsconfig path alias ' + key + ' has no target')\n\t\treturn Object.assign(aliases, { [key]: resolveWorkspacePath(path) })\n\t}, {}),\n}\n\n{{factories}}export default defineConfig({\n\tresolve,\n\ttest: {\n{{projects}}\n\t},\n})\n";
1037
+ vite: "import type { {{viteTypes}} } from 'vite'\n{{imports}}import { defineConfig, mergeConfig } from 'vitest/config'\nimport tsconfig from './tsconfig.json' with { type: 'json' }\n{{helpers}}{{browsers}}import { fileURLToPath, URL } from 'node:url'\n\n{{options}}export function resolveWorkspacePath(relativePath: string): string {\n\treturn fileURLToPath(new URL(relativePath, import.meta.url))\n}\n\nconst resolve = {\n\talias: Object.entries(tsconfig.compilerOptions.paths).reduce((aliases, [key, values]) => {\n\t\tconst [path] = values\n\t\tif (path === undefined) throw new Error('tsconfig path alias ' + key + ' has no target')\n\t\treturn Object.assign(aliases, { [key]: resolveWorkspacePath(path) })\n\t}, {}),\n}\n\n{{factories}}export default defineConfig({\n\tresolve,\n\ttest: {\n{{projects}}\n\t},\n})\n";
1030
1038
  }>;
1031
1039
  factories: Readonly<{
1032
1040
  src: Readonly<{
1033
1041
  core: "export const srcCore = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:core', color: 'magenta' },\n\t\t\t\tinclude: ['tests/src/core/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1034
1042
  browser: "export const srcBrowser = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/browser/index.ts'),\n\t\t\t\t\tformats: ['es'],\n\t\t\t\t\tfileName: () => 'index.js',\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/src/browser',\n\t\t\t\trolldownOptions: {\n\t\t\t\t\t{{external}}\n{{output}}\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:browser', color: 'yellow' },\n\t\t\t\tinclude: ['tests/src/browser/**/*.test.ts'],\n{{exclude}}\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],\n{{global}}\n\t\t\t\tbrowser: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tprovider: playwright(browserOptions),\n\t\t\t\t\tinstances: [{ browser: 'chromium', headless: true }],\n\t\t\t\t},\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1035
1043
  server: "export const srcServer = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/server/index.ts'),\n\t\t\t\t\tformats: ['es', 'cjs'],\n\t\t\t\t\tfileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/src/server',\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: {\n\t\t\t\t\tplatform: 'node',\n\t\t\t\t\t{{external}}\n{{output}}\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:server', color: 'red' },\n\t\t\t\tinclude: ['tests/src/server/**/*.test.ts'],\n{{exclude}}\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1036
- bin: "export const srcBin = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/bin')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/bin/main.ts'),\n\t\t\t\t\tformats: ['es'],\n\t\t\t\t\tfileName: () => 'main.js',\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/bin',\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: { external: [/^node:/, /^@orkestrel\\//, /^@src\\//] },\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:bin', color: 'yellow' },\n\t\t\t\tinclude: ['tests/src/bin/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1044
+ bin: "export const srcBin = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/bin')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/bin/main.ts'),\n\t\t\t\t\tformats: ['es'],\n\t\t\t\t\tfileName: () => 'main.js',\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/bin',\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: { external: [/^node:/, /^@orkestrel\\//, /^@src\\//] },\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:bin', color: 'yellow' },\n\t\t\t\tinclude: ['tests/src/bin/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t\t// A bin test drives the real executable over a real temporary repository, so it\n\t\t\t\t// spends seconds in process startup and filesystem work rather than milliseconds.\n\t\t\t\t// Vitest's five-second default clears one alone and times out under a full suite.\n\t\t\t\ttestTimeout: 15_000,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1037
1045
  }>;
1038
1046
  app: Readonly<{
1039
1047
  core: "export const appCore = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [environmentBoundary('app/core')],\n\t\t\ttest: {\n\t\t\t\tname: { label: 'app:core', color: 'cyan' },\n\t\t\t\tinclude: ['tests/app/core/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1040
- browser: "function applicationBrowser(showcase: boolean): UserConfig {\n\tconst output = showcase ? 'dist/showcase' : 'dist/app/browser'\n{{showcasePlugins}}\treturn {\n\t\tresolve,\n{{plugins}}\t\troot: resolveWorkspacePath('app/browser'),\n\t\tpublicDir: false,\n\t\tbuild: {\n{{showcaseBuild}}\t\t\temptyOutDir: true,\n\t\t\toutDir: resolveWorkspacePath(output),\n\t\t\trolldownOptions: { input: resolveWorkspacePath('app/browser/index.html') },\n\t\t},\n\t\ttest: {\n\t\t\tname: { label: 'app:browser', color: 'blue' },\n\t\t\troot: resolveWorkspacePath('.'),\n\t\t\tdir: resolveWorkspacePath('.'),\n\t\t\tinclude: ['tests/app/browser/**/*.test.ts'],\n\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],\n\t\t\tbrowser: {\n\t\t\t\tenabled: true,\n\t\t\t\tprovider: playwright(browserOptions),\n\t\t\t\tinstances: [{ browser: 'chromium', headless: true }],\n\t\t\t},\n\t\t\tfileParallelism: false,\n\t\t},\n\t}\n}\n\nexport function appBrowser(...options: never[]): UserConfig {\n\tif (options.length > 0) throw new Error('Browser configuration overrides are not permitted')\n\treturn applicationBrowser(false)\n}\n{{showcaseFactory}}";
1048
+ browser: "function applicationBrowser(showcase: boolean): UserConfig {\n\tconst output = showcase ? 'dist/showcase' : 'dist/app/browser'\n{{showcasePlugins}}\treturn {\n\t\tresolve,\n{{plugins}}\t\troot: resolveWorkspacePath('app/browser'),\n\t\tpublicDir: false,\n\t\tbuild: {\n{{showcaseBuild}}\t\t\temptyOutDir: true,\n\t\t\toutDir: resolveWorkspacePath(output),\n\t\t\trolldownOptions: { input: resolveWorkspacePath('app/browser/index.html') },\n\t\t},\n\t\ttest: {\n\t\t\tname: { label: 'app:browser', color: 'blue' },\n\t\t\troot: resolveWorkspacePath('.'),\n\t\t\tdir: resolveWorkspacePath('.'),\n\t\t\tinclude: ['tests/app/browser/**/*.test.ts'],\n\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],\n\t\t\tbrowser: {\n\t\t\t\tenabled: true,\n\t\t\t\tprovider: playwright(browserOptions),\n\t\t\t\tinstances: [{ browser: 'chromium', headless: true }],\n\t\t\t},\n\t\t\tfileParallelism: false,\n\t\t},\n\t}\n}\n\nexport function appBrowser(): UserConfig {\n\treturn applicationBrowser(false)\n}\n{{showcaseFactory}}";
1041
1049
  server: "export const appServer = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/app/server'), environmentBoundary('app/server')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('app/server/main.ts'),\n\t\t\t\t\tformats: ['cjs'],\n\t\t\t\t\tfileName: () => 'main.cjs',\n\t\t\t\t},\n\t\t\t\toutDir: resolveWorkspacePath('dist/app/server'),\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: { external: (id: string) => id.startsWith('node:') },\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'app:server', color: 'green' },\n\t\t\t\tinclude: ['tests/app/server/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1042
1050
  }>;
1043
1051
  policy: "export const policy = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'policy', color: 'white' },\n\t\t\t\tinclude: ['tests/policy.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
@@ -1045,8 +1053,9 @@ export declare class Compiler implements CompilerInterface {
1045
1053
  guides: "export const guides = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'guides', color: 'green' },\n\t\t\t\tinclude: ['tests/guides.test.ts'],\n\t\t\t\texclude: ['tests/src/**/*.test.ts', 'tests/app/**/*.test.ts', 'tests/setup.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1046
1054
  conformance: "// Where this package drifts from the official tooling it stays compatible with.\n// The subject is this package, so the proof is hermetic and stays in `npm test`.\nexport const conformance = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'conformance', color: 'magenta' },\n\t\t\t\tinclude: ['tests/conformance.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1047
1055
  service: "// The live external services this package drives. It starts nothing itself:\n// `scripts/service.sh` provisions, `tests/setupService.ts` proves readiness, and\n// the project stays out of `npm test` because a real service answers it.\nexport const service = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'service', color: 'red' },\n\t\t\t\tinclude: ['tests/service/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupService.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1056
+ distribution: "export const distribution = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'distribution', color: 'cyan' },\n\t\t\t\tinclude: ['tests/distribution.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1048
1057
  probe: "// A workbench, not a proof. No gate selects this project.\nexport const probe = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'probe', color: 'gray' },\n\t\t\t\tinclude: ['tmp/probe/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1049
- integration: "export const integration = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'integration', color: 'blue' },\n\t\t\t\tinclude: ['tests/integration.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n{{global}}\t\t\t\tenvironment: 'node',\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1058
+ integration: "export const integration = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'integration', color: 'blue' },\n\t\t\t\tinclude: ['tests/integration.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n{{global}}\t\t\t\tenvironment: 'node',\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1050
1059
  }>;
1051
1060
  tsconfigs: Readonly<{
1052
1061
  src: Readonly<{
@@ -1169,6 +1178,9 @@ export declare class Compiler implements CompilerInterface {
1169
1178
  */
1170
1179
  export declare function createCompiler(options?: CompilerOptions): CompilerInterface;
1171
1180
 
1181
+ /** The development dependencies that emit declarations for published source or an executable. */
1182
+ export declare const DECLARATION_DEV_DEPENDENCIES: Readonly<Record<string, string>>;
1183
+
1172
1184
  /** The `engines.node` range a workspace starts with. */
1173
1185
  export declare const DEFAULT_ENGINES = ">=22.12.0";
1174
1186
 
@@ -1235,6 +1247,9 @@ export declare class Compiler implements CompilerInterface {
1235
1247
  */
1236
1248
  export declare const DEPENDENCY_NAME_PATTERN: RegExp;
1237
1249
 
1250
+ /** The packed-package proof whose presence makes a workspace `distribution`. */
1251
+ export declare const DISTRIBUTION_TEST_PATH = "tests/distribution.test.ts";
1252
+
1238
1253
  /**
1239
1254
  * How one target path compares to the artifact planned for it.
1240
1255
  *
@@ -1385,7 +1400,7 @@ export declare class Compiler implements CompilerInterface {
1385
1400
  */
1386
1401
  export declare const GROUPS: readonly Group[];
1387
1402
 
1388
- /** The guide-parity proof whose physical file selects the fixed `guides` project. */
1403
+ /** The guide-parity proof whose presence selects the planned `guides` project. */
1389
1404
  export declare const GUIDES_TEST_PATH = "tests/guides.test.ts";
1390
1405
 
1391
1406
  /** Exact lowercase hexadecimal bytes: two digits per byte, and empty content is valid. */
@@ -1416,7 +1431,9 @@ export declare class Compiler implements CompilerInterface {
1416
1431
  * exist. That is why the ownership here is narrowed away from `content`: a
1417
1432
  * claim over bytes nobody has read is a claim that cannot be checked. Reading
1418
1433
  * the vendored root turns the ones scaffold owns the bytes of into
1419
- * {@link HydratedArtifact}.
1434
+ * {@link HydratedArtifact}. Workspace-owned paths and paths whose bytes belong
1435
+ * to another verb stay plain host artifacts, because this writer claims only
1436
+ * their presence.
1420
1437
  */
1421
1438
  export declare interface HostArtifact extends ArtifactBase {
1422
1439
  readonly origin: 'host';
@@ -1508,7 +1525,7 @@ export declare class Compiler implements CompilerInterface {
1508
1525
  */
1509
1526
  export declare function inferGroup(path: string): Group;
1510
1527
 
1511
- /** The installed-package proof whose presence makes a workspace `integration`. */
1528
+ /** The cross-environment composition proof whose presence makes a workspace `integration`. */
1512
1529
  export declare const INTEGRATION_TEST_PATH = "tests/integration.test.ts";
1513
1530
 
1514
1531
  /** Visible characters a target-relative path and a Markdown path cell both forbid. */
@@ -1962,6 +1979,29 @@ export declare class Compiler implements CompilerInterface {
1962
1979
  */
1963
1980
  export declare function matchesOrchestrationPath(path: string): boolean;
1964
1981
 
1982
+ /**
1983
+ * Test whether one emitted line fits the vendored formatter width.
1984
+ *
1985
+ * @param line - One emitted line, leading tabs included.
1986
+ * @returns `true` when the expanded line fits.
1987
+ *
1988
+ * @remarks
1989
+ * A generator writes source the formatter then reads back, so a line packed
1990
+ * past the vendored width is rewrapped on the next `format` run and the emitted
1991
+ * bytes stop matching the plan the audit compares against. The generator
1992
+ * therefore measures a candidate line and chooses the shape the formatter would
1993
+ * have chosen. Tabs are expanded first because the formatter counts them as
1994
+ * `TAB_WIDTH` columns rather than as one character.
1995
+ *
1996
+ * @example
1997
+ * ```ts
1998
+ * import { matchesPrintWidth } from '@orkestrel/scaffold'
1999
+ *
2000
+ * matchesPrintWidth('\t\tprojects: [core],') // true
2001
+ * ```
2002
+ */
2003
+ export declare function matchesPrintWidth(line: string): boolean;
2004
+
1965
2005
  /**
1966
2006
  * Test whether a declared range already admits a published version.
1967
2007
  *
@@ -2470,6 +2510,9 @@ export declare class Compiler implements CompilerInterface {
2470
2510
  */
2471
2511
  export declare function planToSummary(plan: Plan): PlanSummary;
2472
2512
 
2513
+ /** Columns one emitted line may occupy, matching `printWidth` in `.oxfmtrc.json`. */
2514
+ export declare const PRINT_WIDTH = 100;
2515
+
2473
2516
  /**
2474
2517
  * One validation issue raised against a blueprint or a plan.
2475
2518
  *
@@ -2771,6 +2814,9 @@ export declare class Compiler implements CompilerInterface {
2771
2814
  */
2772
2815
  export declare function srcToRoot(src: readonly Environment[]): Environment | undefined;
2773
2816
 
2817
+ /** Columns one tab occupies when the formatter measures a line, matching `tabWidth`. */
2818
+ export declare const TAB_WIDTH = 2;
2819
+
2774
2820
  /** The exact three-component version syntax a blueprint declares. */
2775
2821
  export declare const VERSION_PATTERN: RegExp;
2776
2822
 
@@ -2793,4 +2839,15 @@ export declare class Compiler implements CompilerInterface {
2793
2839
  readonly showcase: boolean;
2794
2840
  }
2795
2841
 
2842
+ /**
2843
+ * The vendored paths whose present bytes belong to each workspace, frozen.
2844
+ *
2845
+ * @remarks
2846
+ * These paths are copied into a workspace when absent and are never compared
2847
+ * or replaced while present. A workspace therefore stops receiving later
2848
+ * canonical updates to them. `.gitignore` takes that trade because its correct
2849
+ * rules differ by workspace, so scaffold cannot own its bytes.
2850
+ */
2851
+ export declare const WORKSPACE_OWNED_PATHS: readonly string[];
2852
+
2796
2853
  export { }
@@ -95,7 +95,7 @@ export declare const ARTIFACT_TEMPLATES: Readonly<{
95
95
  global: "export function setup(): void {}\n";
96
96
  entry: "import * as entry from {{specifier}}\nimport { describe, expect, it } from 'vitest'\n\ndescribe({{label}}, () => {\n\tit('has no starter exports', () => {\n\t\texpect(Object.keys(entry)).toStrictEqual([])\n\t})\n})\n";
97
97
  bin: "import { describe, expect, it } from 'vitest'\n\ndescribe('bin entry', () => {\n\tit('has no starter exports', async () => {\n{{import}}\n\t\texpect(Object.keys(entry)).toStrictEqual([])\n\t})\n})\n";
98
- integration: "import { spawnSync } from 'node:child_process'\nimport { globSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { describe, expect, it } from 'vitest'\n\nconst root = resolve(dirname(fileURLToPath(import.meta.url)), '..')\nconst npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'\nconst registry =\n\tspawnSync(npm, ['ping', '--fetch-retries=0', '--fetch-timeout=1000', '--loglevel=silent'], {\n\t\tcwd: root,\n\t\tstdio: 'ignore',\n\t\ttimeout: 5_000,\n\t\twindowsHide: true,\n\t}).status === 0\n\ndescribe('installed package consumer', () => {\n\tit('loads the built package from a process outside the workspace', () => {\n\t\tconst workspace = mkdtempSync(join(tmpdir(), 'orkestrel-integration-driver-'))\n\t\ttry {\n\t\t\tconst manifest: unknown = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'))\n\t\t\tif (typeof manifest !== 'object' || manifest === null) {\n\t\t\t\tthrow new Error('The package manifest is not a record')\n\t\t\t}\n\t\t\tconst module: unknown = Object.getOwnPropertyDescriptor(manifest, 'module')?.value\n\t\t\tif (typeof module !== 'string')\n\t\t\t\tthrow new Error('The package manifest carries no module entry')\n\t\t\tconst entry = pathToFileURL(resolve(root, module)).href\n\t\t\tconst missing = pathToFileURL(resolve(root, 'dist/outside-integration-control.js')).href\n\t\t\tconst control = spawnSync(\n\t\t\t\tprocess.execPath,\n\t\t\t\t['--input-type=module', '--eval', 'await import(' + JSON.stringify(missing) + ')'],\n\t\t\t\t{ cwd: workspace, encoding: 'utf8', windowsHide: true },\n\t\t\t)\n\t\t\texpect(control.status).not.toBe(0)\n\t\t\tconst driven = spawnSync(\n\t\t\t\tprocess.execPath,\n\t\t\t\t['--input-type=module', '--eval', 'await import(' + JSON.stringify(entry) + ')'],\n\t\t\t\t{ cwd: workspace, encoding: 'utf8', windowsHide: true },\n\t\t\t)\n\t\t\texpect(driven.status).toBe(0)\n\t\t\texpect(driven.stderr).toBe('')\n\t\t} finally {\n\t\t\trmSync(workspace, { recursive: true, force: true })\n\t\t}\n\t})\n\n\tit.skipIf(!registry)(\n\t\t'installs the packed package into an outside consumer [requires a reachable npm registry]',\n\t\t() => {\n\t\t\tconst workspace = mkdtempSync(join(tmpdir(), 'orkestrel-integration-install-'))\n\t\t\tconst packed = join(workspace, 'packed')\n\t\t\tconst consumer = join(workspace, 'consumer')\n\t\t\ttry {\n\t\t\t\tmkdirSync(packed, { recursive: true })\n\t\t\t\tmkdirSync(consumer, { recursive: true })\n\t\t\t\tconst pack = spawnSync(\n\t\t\t\t\tnpm,\n\t\t\t\t\t['pack', '--json', '--ignore-scripts', '--pack-destination', packed],\n\t\t\t\t\t{ cwd: root, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(pack.status).toBe(0)\n\t\t\t\tconst archives = globSync('*.tgz', { cwd: packed })\n\t\t\t\texpect(archives).toHaveLength(1)\n\t\t\t\tconst archive = archives[0]\n\t\t\t\tif (archive === undefined) throw new Error('The package archive was not written')\n\t\t\t\twriteFileSync(\n\t\t\t\t\tjoin(consumer, 'package.json'),\n\t\t\t\t\t'{\"name\":\"outside-consumer\",\"private\":true,\"type\":\"module\"}\\n',\n\t\t\t\t)\n\t\t\t\tconst install = spawnSync(\n\t\t\t\t\tnpm,\n\t\t\t\t\t['install', '--ignore-scripts', '--no-audit', '--no-fund', join(packed, archive)],\n\t\t\t\t\t{ cwd: consumer, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(install.status).toBe(0)\n\t\t\t\tconst manifest: unknown = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'))\n\t\t\t\tif (typeof manifest !== 'object' || manifest === null) {\n\t\t\t\t\tthrow new Error('The package manifest is not a record')\n\t\t\t\t}\n\t\t\t\tconst name: unknown = Object.getOwnPropertyDescriptor(manifest, 'name')?.value\n\t\t\t\tif (typeof name !== 'string') throw new Error('The package manifest carries no name')\n\t\t\t\tconst control = spawnSync(\n\t\t\t\t\tprocess.execPath,\n\t\t\t\t\t[\n\t\t\t\t\t\t'--input-type=module',\n\t\t\t\t\t\t'--eval',\n\t\t\t\t\t\t'await import(' + JSON.stringify(name + '/outside-integration-control') + ')',\n\t\t\t\t\t],\n\t\t\t\t\t{ cwd: consumer, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(control.status).not.toBe(0)\n\t\t\t\tconst driven = spawnSync(\n\t\t\t\t\tprocess.execPath,\n\t\t\t\t\t['--input-type=module', '--eval', 'await import(' + JSON.stringify(name) + ')'],\n\t\t\t\t\t{ cwd: consumer, encoding: 'utf8', windowsHide: true },\n\t\t\t\t)\n\t\t\t\texpect(driven.status).toBe(0)\n\t\t\t\texpect(driven.stderr).toBe('')\n\t\t\t} finally {\n\t\t\t\trmSync(workspace, { recursive: true, force: true })\n\t\t\t}\n\t\t},\n\t\t300_000,\n\t)\n})\n";
98
+ integration: "{{imports}}import { describe, expect, it } from 'vitest'\n\ndescribe('workspace integration', () => {\n\tit('loads every selected public barrel together as a composition seed', () => {\n\t\t// Replace this empty-barrel seed with one observable flow that passes one\n\t\t// environment's public result into another.\n\t\t{{actual}}{{expected}})\n\t})\n})\n";
99
99
  }>;
100
100
  docs: Readonly<{
101
101
  readme: "# {{package}}\n\n{{description}}\n\n## Development\n\n```sh\nnpm install\nnpm test\n```\n";
@@ -235,15 +235,14 @@ export declare const BIN_ENTRY_PATH = "src/bin/main.ts";
235
235
  * application-only, and mixed workspaces are all first class. `dependencies`
236
236
  * and `peers` are runtime `@orkestrel/*` packages; `extras` are
237
237
  * package-specific development dependencies and may carry any valid npm name.
238
- * `bin`, `integration`, `conformance`, `service`, `vendors`, `global`, and
239
- * `showcase` are structural facts: each is set only when the workspace
240
- * physically ships the directory or exact-case file that defines it, never
241
- * because of the workspace's name and never because a sibling fact is set. An
242
- * axis-dependent fact projects nothing when its required axis is absent:
243
- * `integration` projects only a published `src`, and `showcase` projects only a
244
- * browser `app`. The gate answers that case with a non-blocking question, so a
245
- * caller that set the flag learns it emitted nothing and the compile still
246
- * completes.
238
+ * `bin`, `guides`, `distribution`, `integration`, `conformance`, `service`,
239
+ * `vendors`, `global`, and `showcase` are structural facts: each is set only
240
+ * when the workspace physically ships the directory or exact-case file that
241
+ * defines it, never because of the workspace's name and never because a sibling
242
+ * fact is set.
243
+ * `showcase` projects only a browser `app`. The gate answers an absent browser
244
+ * axis with a non-blocking question, so a caller that set the flag learns it
245
+ * emitted nothing and the compile still completes.
247
246
  *
248
247
  * `service` says the workspace runs a live-service Vitest project over
249
248
  * `tests/service`, and it alone registers that project. `vendors` names each
@@ -265,6 +264,8 @@ export declare interface Blueprint {
265
264
  readonly engines: string;
266
265
  readonly overrides: readonly Override[];
267
266
  readonly bin: boolean;
267
+ readonly guides: boolean;
268
+ readonly distribution: boolean;
268
269
  readonly integration: boolean;
269
270
  readonly conformance: boolean;
270
271
  readonly service: boolean;
@@ -438,12 +439,19 @@ export declare function blueprintToOrchestrationArtifacts(blueprint: Blueprint):
438
439
  *
439
440
  * A question blocks when it describes a workspace this package cannot generate.
440
441
  * Three do not, because each describes a workspace it can describe honestly and
441
- * should not create: a published axis of several environments without core, whose
442
- * manifest names a core build the workspace never runs, and a structural flag
443
- * whose required axis is absent, which emits nothing. Blocking those closed the
444
- * gate for every verb, and the verbs that read an existing workspace need the
445
- * plan the gate refused. The caller that chooses the shape refuses the advisory;
446
- * the callers that read one report it.
442
+ * should not create: a published axis of several environments without core,
443
+ * whose manifest names a core build the workspace never runs; a showcase flag
444
+ * whose required browser axis is absent, which emits nothing; and an
445
+ * integration flag over fewer than two environments, whose seed does emit and
446
+ * has nothing to compose across. Blocking any of them closed the gate for every
447
+ * verb. The verbs that read an existing workspace need the plan the gate
448
+ * refused. The caller that chooses the shape refuses the advisory; the callers
449
+ * that read one report it.
450
+ *
451
+ * The integration advisory counts both axes together, because the proof it
452
+ * seeds spans environments rather than published ones: an application of two
453
+ * environments composes, and a package publishing one does not. Reading either
454
+ * axis alone withdrew the proof from a workspace that does compose.
447
455
  *
448
456
  * An environment question carries `ENVIRONMENTS` as its candidates, so a caller
449
457
  * reads the accepted values from the question instead of from the documentation.
@@ -511,12 +519,13 @@ export declare function blueprintToRootVite(blueprint: Blueprint): string;
511
519
  * proofs every workspace can pass before it has a public API, and one build per
512
520
  * target that actually builds.
513
521
  *
514
- * A proof leaves `test` when a real service or a real install answers it. The
515
- * installed-package integration proof and the live-service proof therefore run
516
- * from `prepublishOnly` instead. The conformance proof stays in `test`, because
517
- * it measures this package against official tooling and drives nothing external:
518
- * a conformance run may start a server, but it starts its own and reaches it
519
- * over loopback, so the run stays hermetic.
522
+ * A publishing workspace isolates distribution and live-service proofs from
523
+ * `test` and runs them from `prepublishOnly` instead. A private workspace has
524
+ * no publish lifecycle, so it omits distribution and runs a live-service proof
525
+ * from `test`. Integration and conformance stay in `test` because they neither
526
+ * pack nor install the workspace and drive no external service. A conformance
527
+ * run may start a server, but it starts its own and reaches it over loopback,
528
+ * so the run stays hermetic.
520
529
  *
521
530
  * The configuration paths interpolated here are the same ones `SRC_MATRIX` and
522
531
  * `APP_MATRIX` list as each environment's configuration files, so a rename in
@@ -562,15 +571,14 @@ export declare function blueprintToSourceArtifacts(blueprint: Blueprint): readon
562
571
  * Compile every artifact in the `tests` group that is not vendored from the host.
563
572
  *
564
573
  * @param blueprint - The workspace specification.
565
- * @returns Shared setup modules, axis tests, and the optional install proof.
574
+ * @returns Shared setup modules, axis tests, and the optional integration seed.
566
575
  *
567
576
  * @remarks
568
577
  * `tests/setupPolicy.ts`, `tests/policy.test.ts`, and `tests/config.test.ts` are
569
578
  * fleet-invariant host artifacts and therefore do not appear here. A guide
570
579
  * proof is not emitted while the workspace intentionally has empty barrels and
571
- * no package guide. The install proof is meaningful only for a published
572
- * workspace and therefore follows the `src` axis as well as its structural
573
- * flag.
580
+ * no package guide. The integration seed follows its structural flag and loads
581
+ * every selected environment through its public barrel.
574
582
  *
575
583
  * The conformance proof is not emitted either, for the reason the guide proof
576
584
  * is not: it names an official artifact only the package knows, so a generated
@@ -1026,18 +1034,18 @@ export declare class Compiler implements CompilerInterface {
1026
1034
  export declare const CONFIG_TEMPLATES: Readonly<{
1027
1035
  root: Readonly<{
1028
1036
  tsconfig: "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"ESNext\",\n\t\t\"module\": \"ESNext\",\n\t\t\"moduleResolution\": \"bundler\",\n\t\t\"allowImportingTsExtensions\": true,\n\t\t\"lib\": [\"ESNext\", \"DOM\", \"DOM.Iterable\"],\n\t\t\"types\": [\"node\", \"vite/client\", \"vitest/globals\"],\n\t\t\"moduleDetection\": \"force\",\n\t\t\"resolveJsonModule\": true,\n\t\t\"strict\": true,\n\t\t\"verbatimModuleSyntax\": true,\n\t\t\"noUncheckedIndexedAccess\": true,\n\t\t\"noUncheckedSideEffectImports\": true,\n\t\t\"exactOptionalPropertyTypes\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"noUnusedParameters\": true,\n\t\t\"noImplicitOverride\": true,\n\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"noEmit\": true,\n\t\t\"paths\": {\n{{paths}}\n\t\t}\n\t},\n\t\"exclude\": [\"node_modules\", \"dist\", \"tmp\"]\n}\n";
1029
- vite: "import type { {{viteTypes}} } from 'vite'\n{{imports}}import { defineConfig, mergeConfig } from 'vitest/config'\nimport tsconfig from './tsconfig.json' with { type: 'json' }\n{{helpers}}{{browsers}}import { lstatSync, readdirSync, realpathSync } from 'node:fs'\nimport { basename, join, parse, relative, resolve as resolvePath, sep } from 'node:path'\nimport { fileURLToPath, URL } from 'node:url'\n\n{{options}}export function resolveWorkspacePath(relativePath: string): string {\n\treturn fileURLToPath(new URL(relativePath, import.meta.url))\n}\n\n// A generated root config must classify its own fixed proof without importing\n// package source, so the exact-case check stays self-contained over Node APIs.\nfunction isExactCaseFile(path: string): boolean {\n\tconst full = resolvePath(path)\n\ttry {\n\t\tconst status = lstatSync(full)\n\t\tif (!status.isFile() || status.isSymbolicLink() || status.nlink !== 1) return false\n\t\tconst root = parse(full).root\n\t\tconst segments = relative(root, full).split(sep)\n\t\tlet parent = root\n\t\tfor (const segment of segments) {\n\t\t\ttry {\n\t\t\t\tif (!readdirSync(parent).includes(segment)) return false\n\t\t\t} catch {\n\t\t\t\tif (basename(realpathSync.native(join(parent, segment))) !== segment) return false\n\t\t\t}\n\t\t\tparent = join(parent, segment)\n\t\t}\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\nconst resolve = {\n\talias: Object.entries(tsconfig.compilerOptions.paths).reduce((aliases, [key, values]) => {\n\t\tconst [path] = values\n\t\tif (path === undefined) throw new Error('tsconfig path alias ' + key + ' has no target')\n\t\treturn Object.assign(aliases, { [key]: resolveWorkspacePath(path) })\n\t}, {}),\n}\n\n{{factories}}export default defineConfig({\n\tresolve,\n\ttest: {\n{{projects}}\n\t},\n})\n";
1037
+ vite: "import type { {{viteTypes}} } from 'vite'\n{{imports}}import { defineConfig, mergeConfig } from 'vitest/config'\nimport tsconfig from './tsconfig.json' with { type: 'json' }\n{{helpers}}{{browsers}}import { fileURLToPath, URL } from 'node:url'\n\n{{options}}export function resolveWorkspacePath(relativePath: string): string {\n\treturn fileURLToPath(new URL(relativePath, import.meta.url))\n}\n\nconst resolve = {\n\talias: Object.entries(tsconfig.compilerOptions.paths).reduce((aliases, [key, values]) => {\n\t\tconst [path] = values\n\t\tif (path === undefined) throw new Error('tsconfig path alias ' + key + ' has no target')\n\t\treturn Object.assign(aliases, { [key]: resolveWorkspacePath(path) })\n\t}, {}),\n}\n\n{{factories}}export default defineConfig({\n\tresolve,\n\ttest: {\n{{projects}}\n\t},\n})\n";
1030
1038
  }>;
1031
1039
  factories: Readonly<{
1032
1040
  src: Readonly<{
1033
1041
  core: "export const srcCore = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:core', color: 'magenta' },\n\t\t\t\tinclude: ['tests/src/core/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1034
1042
  browser: "export const srcBrowser = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/src/browser'), environmentBoundary('src/browser')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/browser/index.ts'),\n\t\t\t\t\tformats: ['es'],\n\t\t\t\t\tfileName: () => 'index.js',\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/src/browser',\n\t\t\t\trolldownOptions: {\n\t\t\t\t\t{{external}}\n{{output}}\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:browser', color: 'yellow' },\n\t\t\t\tinclude: ['tests/src/browser/**/*.test.ts'],\n{{exclude}}\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],\n{{global}}\n\t\t\t\tbrowser: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tprovider: playwright(browserOptions),\n\t\t\t\t\tinstances: [{ browser: 'chromium', headless: true }],\n\t\t\t\t},\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1035
1043
  server: "export const srcServer = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/src/server'), environmentBoundary('src/server')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/server/index.ts'),\n\t\t\t\t\tformats: ['es', 'cjs'],\n\t\t\t\t\tfileName: (format: string) => (format === 'es' ? 'index.js' : 'index.cjs'),\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/src/server',\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: {\n\t\t\t\t\tplatform: 'node',\n\t\t\t\t\t{{external}}\n{{output}}\n\t\t\t\t},\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:server', color: 'red' },\n\t\t\t\tinclude: ['tests/src/server/**/*.test.ts'],\n{{exclude}}\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1036
- bin: "export const srcBin = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/bin')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/bin/main.ts'),\n\t\t\t\t\tformats: ['es'],\n\t\t\t\t\tfileName: () => 'main.js',\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/bin',\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: { external: [/^node:/, /^@orkestrel\\//, /^@src\\//] },\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:bin', color: 'yellow' },\n\t\t\t\tinclude: ['tests/src/bin/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1044
+ bin: "export const srcBin = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/bin')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tsourcemap: true,\n\t\t\t\tminify: false,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('src/bin/main.ts'),\n\t\t\t\t\tformats: ['es'],\n\t\t\t\t\tfileName: () => 'main.js',\n\t\t\t\t},\n\t\t\t\toutDir: 'dist/bin',\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: { external: [/^node:/, /^@orkestrel\\//, /^@src\\//] },\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'src:bin', color: 'yellow' },\n\t\t\t\tinclude: ['tests/src/bin/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t\t// A bin test drives the real executable over a real temporary repository, so it\n\t\t\t\t// spends seconds in process startup and filesystem work rather than milliseconds.\n\t\t\t\t// Vitest's five-second default clears one alone and times out under a full suite.\n\t\t\t\ttestTimeout: 15_000,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1037
1045
  }>;
1038
1046
  app: Readonly<{
1039
1047
  core: "export const appCore = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [environmentBoundary('app/core')],\n\t\t\ttest: {\n\t\t\t\tname: { label: 'app:core', color: 'cyan' },\n\t\t\t\tinclude: ['tests/app/core/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1040
- browser: "function applicationBrowser(showcase: boolean): UserConfig {\n\tconst output = showcase ? 'dist/showcase' : 'dist/app/browser'\n{{showcasePlugins}}\treturn {\n\t\tresolve,\n{{plugins}}\t\troot: resolveWorkspacePath('app/browser'),\n\t\tpublicDir: false,\n\t\tbuild: {\n{{showcaseBuild}}\t\t\temptyOutDir: true,\n\t\t\toutDir: resolveWorkspacePath(output),\n\t\t\trolldownOptions: { input: resolveWorkspacePath('app/browser/index.html') },\n\t\t},\n\t\ttest: {\n\t\t\tname: { label: 'app:browser', color: 'blue' },\n\t\t\troot: resolveWorkspacePath('.'),\n\t\t\tdir: resolveWorkspacePath('.'),\n\t\t\tinclude: ['tests/app/browser/**/*.test.ts'],\n\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],\n\t\t\tbrowser: {\n\t\t\t\tenabled: true,\n\t\t\t\tprovider: playwright(browserOptions),\n\t\t\t\tinstances: [{ browser: 'chromium', headless: true }],\n\t\t\t},\n\t\t\tfileParallelism: false,\n\t\t},\n\t}\n}\n\nexport function appBrowser(...options: never[]): UserConfig {\n\tif (options.length > 0) throw new Error('Browser configuration overrides are not permitted')\n\treturn applicationBrowser(false)\n}\n{{showcaseFactory}}";
1048
+ browser: "function applicationBrowser(showcase: boolean): UserConfig {\n\tconst output = showcase ? 'dist/showcase' : 'dist/app/browser'\n{{showcasePlugins}}\treturn {\n\t\tresolve,\n{{plugins}}\t\troot: resolveWorkspacePath('app/browser'),\n\t\tpublicDir: false,\n\t\tbuild: {\n{{showcaseBuild}}\t\t\temptyOutDir: true,\n\t\t\toutDir: resolveWorkspacePath(output),\n\t\t\trolldownOptions: { input: resolveWorkspacePath('app/browser/index.html') },\n\t\t},\n\t\ttest: {\n\t\t\tname: { label: 'app:browser', color: 'blue' },\n\t\t\troot: resolveWorkspacePath('.'),\n\t\t\tdir: resolveWorkspacePath('.'),\n\t\t\tinclude: ['tests/app/browser/**/*.test.ts'],\n\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupBrowser.ts'],\n\t\t\tbrowser: {\n\t\t\t\tenabled: true,\n\t\t\t\tprovider: playwright(browserOptions),\n\t\t\t\tinstances: [{ browser: 'chromium', headless: true }],\n\t\t\t},\n\t\t\tfileParallelism: false,\n\t\t},\n\t}\n}\n\nexport function appBrowser(): UserConfig {\n\treturn applicationBrowser(false)\n}\n{{showcaseFactory}}";
1041
1049
  server: "export const appServer = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\tpublicDir: false,\n\t\t\tplugins: [outputBoundary('dist/app/server'), environmentBoundary('app/server')],\n\t\t\tbuild: {\n\t\t\t\temptyOutDir: true,\n\t\t\t\tlib: {\n\t\t\t\t\tentry: resolveWorkspacePath('app/server/main.ts'),\n\t\t\t\t\tformats: ['cjs'],\n\t\t\t\t\tfileName: () => 'main.cjs',\n\t\t\t\t},\n\t\t\t\toutDir: resolveWorkspacePath('dist/app/server'),\n\t\t\t\ttarget: 'node22',\n\t\t\t\trolldownOptions: { external: (id: string) => id.startsWith('node:') },\n\t\t\t},\n\t\t\ttest: {\n\t\t\t\tname: { label: 'app:server', color: 'green' },\n\t\t\t\tinclude: ['tests/app/server/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupServer.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1042
1050
  }>;
1043
1051
  policy: "export const policy = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'policy', color: 'white' },\n\t\t\t\tinclude: ['tests/policy.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
@@ -1045,8 +1053,9 @@ export declare class Compiler implements CompilerInterface {
1045
1053
  guides: "export const guides = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'guides', color: 'green' },\n\t\t\t\tinclude: ['tests/guides.test.ts'],\n\t\t\t\texclude: ['tests/src/**/*.test.ts', 'tests/app/**/*.test.ts', 'tests/setup.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1046
1054
  conformance: "// Where this package drifts from the official tooling it stays compatible with.\n// The subject is this package, so the proof is hermetic and stays in `npm test`.\nexport const conformance = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'conformance', color: 'magenta' },\n\t\t\t\tinclude: ['tests/conformance.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1047
1055
  service: "// The live external services this package drives. It starts nothing itself:\n// `scripts/service.sh` provisions, `tests/setupService.ts` proves readiness, and\n// the project stays out of `npm test` because a real service answers it.\nexport const service = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'service', color: 'red' },\n\t\t\t\tinclude: ['tests/service/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts', './tests/setupService.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1056
+ distribution: "export const distribution = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'distribution', color: 'cyan' },\n\t\t\t\tinclude: ['tests/distribution.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1048
1057
  probe: "// A workbench, not a proof. No gate selects this project.\nexport const probe = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'probe', color: 'gray' },\n\t\t\t\tinclude: ['tmp/probe/**/*.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n\t\t\t\tenvironment: 'node',\n\t\t\t\tbrowser: { enabled: false },\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1049
- integration: "export const integration = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'integration', color: 'blue' },\n\t\t\t\tinclude: ['tests/integration.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n{{global}}\t\t\t\tenvironment: 'node',\n\t\t\t\ttestTimeout: 120_000,\n\t\t\t\thookTimeout: 120_000,\n\t\t\t\tfileParallelism: false,\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1058
+ integration: "export const integration = (options?: UserConfig): UserConfig =>\n\tmergeConfig(\n\t\t{\n\t\t\tresolve,\n\t\t\ttest: {\n\t\t\t\tname: { label: 'integration', color: 'blue' },\n\t\t\t\tinclude: ['tests/integration.test.ts'],\n\t\t\t\tsetupFiles: ['./tests/setup.ts'],\n{{global}}\t\t\t\tenvironment: 'node',\n\t\t\t},\n\t\t},\n\t\toptions ?? {},\n\t)\n";
1050
1059
  }>;
1051
1060
  tsconfigs: Readonly<{
1052
1061
  src: Readonly<{
@@ -1169,6 +1178,9 @@ export declare class Compiler implements CompilerInterface {
1169
1178
  */
1170
1179
  export declare function createCompiler(options?: CompilerOptions): CompilerInterface;
1171
1180
 
1181
+ /** The development dependencies that emit declarations for published source or an executable. */
1182
+ export declare const DECLARATION_DEV_DEPENDENCIES: Readonly<Record<string, string>>;
1183
+
1172
1184
  /** The `engines.node` range a workspace starts with. */
1173
1185
  export declare const DEFAULT_ENGINES = ">=22.12.0";
1174
1186
 
@@ -1235,6 +1247,9 @@ export declare class Compiler implements CompilerInterface {
1235
1247
  */
1236
1248
  export declare const DEPENDENCY_NAME_PATTERN: RegExp;
1237
1249
 
1250
+ /** The packed-package proof whose presence makes a workspace `distribution`. */
1251
+ export declare const DISTRIBUTION_TEST_PATH = "tests/distribution.test.ts";
1252
+
1238
1253
  /**
1239
1254
  * How one target path compares to the artifact planned for it.
1240
1255
  *
@@ -1385,7 +1400,7 @@ export declare class Compiler implements CompilerInterface {
1385
1400
  */
1386
1401
  export declare const GROUPS: readonly Group[];
1387
1402
 
1388
- /** The guide-parity proof whose physical file selects the fixed `guides` project. */
1403
+ /** The guide-parity proof whose presence selects the planned `guides` project. */
1389
1404
  export declare const GUIDES_TEST_PATH = "tests/guides.test.ts";
1390
1405
 
1391
1406
  /** Exact lowercase hexadecimal bytes: two digits per byte, and empty content is valid. */
@@ -1416,7 +1431,9 @@ export declare class Compiler implements CompilerInterface {
1416
1431
  * exist. That is why the ownership here is narrowed away from `content`: a
1417
1432
  * claim over bytes nobody has read is a claim that cannot be checked. Reading
1418
1433
  * the vendored root turns the ones scaffold owns the bytes of into
1419
- * {@link HydratedArtifact}.
1434
+ * {@link HydratedArtifact}. Workspace-owned paths and paths whose bytes belong
1435
+ * to another verb stay plain host artifacts, because this writer claims only
1436
+ * their presence.
1420
1437
  */
1421
1438
  export declare interface HostArtifact extends ArtifactBase {
1422
1439
  readonly origin: 'host';
@@ -1508,7 +1525,7 @@ export declare class Compiler implements CompilerInterface {
1508
1525
  */
1509
1526
  export declare function inferGroup(path: string): Group;
1510
1527
 
1511
- /** The installed-package proof whose presence makes a workspace `integration`. */
1528
+ /** The cross-environment composition proof whose presence makes a workspace `integration`. */
1512
1529
  export declare const INTEGRATION_TEST_PATH = "tests/integration.test.ts";
1513
1530
 
1514
1531
  /** Visible characters a target-relative path and a Markdown path cell both forbid. */
@@ -1962,6 +1979,29 @@ export declare class Compiler implements CompilerInterface {
1962
1979
  */
1963
1980
  export declare function matchesOrchestrationPath(path: string): boolean;
1964
1981
 
1982
+ /**
1983
+ * Test whether one emitted line fits the vendored formatter width.
1984
+ *
1985
+ * @param line - One emitted line, leading tabs included.
1986
+ * @returns `true` when the expanded line fits.
1987
+ *
1988
+ * @remarks
1989
+ * A generator writes source the formatter then reads back, so a line packed
1990
+ * past the vendored width is rewrapped on the next `format` run and the emitted
1991
+ * bytes stop matching the plan the audit compares against. The generator
1992
+ * therefore measures a candidate line and chooses the shape the formatter would
1993
+ * have chosen. Tabs are expanded first because the formatter counts them as
1994
+ * `TAB_WIDTH` columns rather than as one character.
1995
+ *
1996
+ * @example
1997
+ * ```ts
1998
+ * import { matchesPrintWidth } from '@orkestrel/scaffold'
1999
+ *
2000
+ * matchesPrintWidth('\t\tprojects: [core],') // true
2001
+ * ```
2002
+ */
2003
+ export declare function matchesPrintWidth(line: string): boolean;
2004
+
1965
2005
  /**
1966
2006
  * Test whether a declared range already admits a published version.
1967
2007
  *
@@ -2470,6 +2510,9 @@ export declare class Compiler implements CompilerInterface {
2470
2510
  */
2471
2511
  export declare function planToSummary(plan: Plan): PlanSummary;
2472
2512
 
2513
+ /** Columns one emitted line may occupy, matching `printWidth` in `.oxfmtrc.json`. */
2514
+ export declare const PRINT_WIDTH = 100;
2515
+
2473
2516
  /**
2474
2517
  * One validation issue raised against a blueprint or a plan.
2475
2518
  *
@@ -2771,6 +2814,9 @@ export declare class Compiler implements CompilerInterface {
2771
2814
  */
2772
2815
  export declare function srcToRoot(src: readonly Environment[]): Environment | undefined;
2773
2816
 
2817
+ /** Columns one tab occupies when the formatter measures a line, matching `tabWidth`. */
2818
+ export declare const TAB_WIDTH = 2;
2819
+
2774
2820
  /** The exact three-component version syntax a blueprint declares. */
2775
2821
  export declare const VERSION_PATTERN: RegExp;
2776
2822
 
@@ -2793,4 +2839,15 @@ export declare class Compiler implements CompilerInterface {
2793
2839
  readonly showcase: boolean;
2794
2840
  }
2795
2841
 
2842
+ /**
2843
+ * The vendored paths whose present bytes belong to each workspace, frozen.
2844
+ *
2845
+ * @remarks
2846
+ * These paths are copied into a workspace when absent and are never compared
2847
+ * or replaced while present. A workspace therefore stops receiving later
2848
+ * canonical updates to them. `.gitignore` takes that trade because its correct
2849
+ * rules differ by workspace, so scaffold cannot own its bytes.
2850
+ */
2851
+ export declare const WORKSPACE_OWNED_PATHS: readonly string[];
2852
+
2796
2853
  export { }