@orkestrel/scaffold 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +34 -17
  2. package/dist/bin/scaffold.js +1162 -1200
  3. package/dist/bin/scaffold.js.map +1 -1
  4. package/dist/host/AGENTS.md +124 -925
  5. package/dist/host/CLAUDE.md +260 -495
  6. package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +53 -0
  7. package/dist/host/agents/skills/orkestrel-align-packages/agents/openai.yaml +4 -0
  8. package/dist/host/agents/skills/orkestrel-align-packages/references/fleet.md +50 -0
  9. package/dist/host/agents/skills/orkestrel-align-packages/references/integration.md +56 -0
  10. package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +64 -0
  11. package/dist/host/agents/skills/orkestrel-build-application/agents/openai.yaml +4 -0
  12. package/dist/host/agents/skills/orkestrel-build-application/references/application.md +129 -0
  13. package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +64 -0
  14. package/dist/host/agents/skills/orkestrel-harden-package/agents/openai.yaml +4 -0
  15. package/dist/host/agents/skills/orkestrel-harden-package/references/centralization.md +85 -0
  16. package/dist/host/agents/skills/orkestrel-harden-package/references/contract.md +57 -0
  17. package/dist/host/agents/skills/orkestrel-harden-package/references/hardening.md +93 -0
  18. package/dist/host/agents/skills/orkestrel-harden-package/references/research.md +61 -0
  19. package/dist/host/claude/agents/application.md +32 -0
  20. package/dist/host/claude/agents/builder.md +12 -7
  21. package/dist/host/claude/agents/checker.md +15 -8
  22. package/dist/host/claude/agents/codex.md +40 -0
  23. package/dist/host/claude/agents/grok.md +20 -37
  24. package/dist/host/claude/agents/orkestrel.md +89 -222
  25. package/dist/host/claude/agents/planner.md +14 -34
  26. package/dist/host/claude/agents/reviewer.md +39 -24
  27. package/dist/host/claude/agents/verifier.md +15 -10
  28. package/dist/host/claude/rules/application.md +57 -0
  29. package/dist/host/claude/rules/architecture.md +179 -0
  30. package/dist/host/claude/rules/browser.md +28 -0
  31. package/dist/host/claude/rules/documentation.md +64 -0
  32. package/dist/host/claude/rules/names.md +209 -0
  33. package/dist/host/claude/rules/patterns.md +130 -0
  34. package/dist/host/claude/rules/quality.md +45 -0
  35. package/dist/host/claude/rules/styles.md +64 -0
  36. package/dist/host/claude/rules/tests.md +123 -0
  37. package/dist/host/claude/rules/typescript.md +78 -0
  38. package/dist/host/claude/rules/workspace.md +180 -0
  39. package/dist/host/claude/settings.json +116 -0
  40. package/dist/host/claude/skills/orkestrel-align-packages/SKILL.md +10 -0
  41. package/dist/host/claude/skills/orkestrel-build-application/SKILL.md +12 -0
  42. package/dist/host/claude/skills/orkestrel-harden-package/SKILL.md +10 -0
  43. package/dist/host/codex/agents/analyst.toml +15 -0
  44. package/dist/host/codex/agents/application.toml +25 -0
  45. package/dist/host/codex/agents/builder.toml +24 -0
  46. package/dist/host/codex/agents/checker.toml +15 -0
  47. package/dist/host/codex/agents/grok.toml +17 -0
  48. package/dist/host/codex/agents/implementer.toml +17 -0
  49. package/dist/host/codex/agents/orkestrel.toml +16 -0
  50. package/dist/host/codex/agents/planner.toml +20 -0
  51. package/dist/host/codex/agents/reviewer.toml +18 -0
  52. package/dist/host/codex/agents/verifier.toml +14 -0
  53. package/dist/host/codex/config.toml +64 -0
  54. package/dist/host/dotfiles/oxlintrc.json +307 -1
  55. package/dist/host/guides/src/scaffold.md +2060 -1970
  56. package/dist/host/manifest.json +355 -137
  57. package/dist/host/scripts/codex.sh +49 -0
  58. package/dist/host/scripts/cursor.sh +33 -47
  59. package/dist/host/scripts/deps.sh +34 -16
  60. package/dist/host/scripts/ollama.sh +6 -149
  61. package/dist/host/tests/setupPolicy.ts +354 -0
  62. package/dist/src/core/index.cjs +6745 -1191
  63. package/dist/src/core/index.cjs.map +1 -1
  64. package/dist/src/core/index.d.cts +923 -273
  65. package/dist/src/core/index.d.ts +923 -273
  66. package/dist/src/core/index.js +6657 -1184
  67. package/dist/src/core/index.js.map +1 -1
  68. package/dist/src/server/index.cjs +3132 -593
  69. package/dist/src/server/index.cjs.map +1 -1
  70. package/dist/src/server/index.d.cts +643 -95
  71. package/dist/src/server/index.d.ts +643 -95
  72. package/dist/src/server/index.js +3054 -594
  73. package/dist/src/server/index.js.map +1 -1
  74. package/package.json +15 -12
  75. package/dist/host/claude/agents/composer.md +0 -64
  76. package/dist/host/claude/agents/researcher.md +0 -38
  77. package/dist/host/claude/agents/scout.md +0 -35
  78. package/dist/host/github/workflows/ci.yml +0 -64
@@ -12,6 +12,7 @@ import { OptionalShape } from '@orkestrel/contract';
12
12
  import { StringShape } from '@orkestrel/contract';
13
13
  import { TableAlign } from '@orkestrel/markdown';
14
14
  import { TemplateDefinition } from '@orkestrel/template';
15
+ import { UnionShape } from '@orkestrel/contract';
15
16
 
16
17
  /**
17
18
  * Build a formatter-width-aligned GFM table string from header and row cells.
@@ -37,12 +38,52 @@ import { TemplateDefinition } from '@orkestrel/template';
37
38
  */
38
39
  export declare function alignTable(header: readonly string[], rows: readonly (readonly string[])[], align?: readonly TableAlign[]): string;
39
40
 
41
+ /** Additional development dependencies required by a private Vue browser application. */
42
+ export declare const APP_BROWSER_DEV_DEPENDENCIES: Readonly<Record<string, string>>;
43
+
44
+ /**
45
+ * The per-environment application matrix: thin config artifacts, Vitest project
46
+ * label, and executable entry where the environment produces a runtime bundle.
47
+ */
48
+ export declare const APP_MATRIX: Readonly<Record<Environment, AppDefinition>>;
49
+
50
+ /** The deterministic config, test-project, and runtime-entry settings for one application environment. */
51
+ export declare interface AppDefinition {
52
+ readonly configs: readonly string[];
53
+ readonly project: string;
54
+ readonly entry?: string;
55
+ }
56
+
57
+ /**
58
+ * Draft the application source artifacts for every selected app environment.
59
+ *
60
+ * @param spec - The blueprint carrying the application environment set.
61
+ * @returns Complete, runnable app/core, app/browser, and app/server artifacts.
62
+ */
63
+ export declare function applicationArtifacts(spec: Blueprint): readonly Artifact[];
64
+
65
+ /**
66
+ * Build the root Vite/Vitest configuration for a workspace that includes
67
+ * app environments, optionally alongside published src environments.
68
+ *
69
+ * @param src - Published src environments.
70
+ * @param app - Private app environments.
71
+ * @param engine - Whether the workspace also builds scaffold's executable.
72
+ * @returns The root `vite.config.ts` content.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * applicationViteConfig([], ['core', 'server']).includes('appServer') // true
77
+ * ```
78
+ */
79
+ export declare function applicationViteConfig(src: readonly Environment[], app: readonly Environment[], engine?: boolean): string;
80
+
40
81
  /**
41
82
  * Apply a blueprint's `overrides` over a drafted artifact list — an override
42
83
  * REPLACES the matching artifact's `content` in place; an override matching
43
- * no planned artifact, or targeting a `host`-origin path, is left unapplied
44
- * here (the gate stage surfaces it as a blocking question — this leaf only
45
- * performs the replacement half of the rule).
84
+ * no planned artifact, targeting a `host`-origin path, or targeting the
85
+ * blueprint-owned `package.json` publication boundary is left unapplied here
86
+ * (the gate stage reports it as a blocking question).
46
87
  *
47
88
  * @param artifacts - The drafted `Artifact[]`.
48
89
  * @param overrides - The blueprint's `overrides`.
@@ -56,38 +97,67 @@ export declare function alignTable(header: readonly string[], rows: readonly (re
56
97
  export declare function applyOverrides(artifacts: readonly Artifact[], overrides: Blueprint['overrides']): readonly Artifact[];
57
98
 
58
99
  /**
59
- * One file in a `Plan`.
100
+ * Build one `configs/app/tsconfig.<environment>.json` check-only configuration.
60
101
  *
61
- * @remarks
62
- * `content` present for `template` / `computed`, `source` (a host-relative
63
- * path) for `host`.
102
+ * @param environment - The application environment.
103
+ * @param hasCore - Whether `app/core` is part of the same workspace.
104
+ * @returns The application environment tsconfig content.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * appTsconfig('browser', true).includes('../../app/core') // true
109
+ * ```
64
110
  */
65
- export declare interface Artifact {
111
+ export declare function appTsconfig(environment: Environment, hasCore: boolean): string;
112
+
113
+ /**
114
+ * Build one thin executable application Vite config.
115
+ *
116
+ * @param environment - The executable browser or server environment.
117
+ * @returns The `configs/app/vite.<environment>.config.ts` content.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * appViteConfig('server').includes('appServer') // true
122
+ * ```
123
+ */
124
+ export declare function appViteConfig(environment: 'browser' | 'server'): string;
125
+
126
+ /** One origin-discriminated file in a `Plan`. */
127
+ export declare type Artifact = HostArtifact | ContentArtifact;
128
+
129
+ /** Fields shared by every file in a `Plan`. */
130
+ export declare interface ArtifactBase {
66
131
  readonly path: string;
67
132
  readonly group: Group;
68
- readonly origin: Origin;
69
- readonly surface?: Surface;
70
- readonly content?: string;
71
- readonly source?: string;
133
+ readonly environment?: Environment;
72
134
  }
73
135
 
74
136
  /**
75
137
  * Build the `Artifact` object shape.
76
138
  *
77
139
  * @remarks
78
- * `origin` is a `literalShape(ORIGINS)`; `content` and `source` are both
79
- * optional (the `origin` axis decides which one a given artifact carries).
140
+ * The `origin` axis is structural: host artifacts may carry `source` and
141
+ * byte `hex`, while template/computed artifacts require text `content`.
142
+ * Lowercase byte-pair validation remains a semantic refinement so the
143
+ * contract generator can continue producing unconstrained strings.
80
144
  *
81
145
  * @returns A fresh `ContractShape` describing one planned file.
82
146
  */
83
- export declare function artifactShape(): ObjectShape<{
147
+ export declare function artifactShape(): UnionShape<[ ObjectShape<{
84
148
  path: StringShape;
85
- group: LiteralShape<readonly ["manifest", "configs", "source", "tests", "guides", "docs", "orchestration"]>;
86
- origin: LiteralShape<readonly ["host", "template", "computed"]>;
87
- surface: OptionalShape<LiteralShape<readonly ["core", "browser", "server"]>>;
88
- content: OptionalShape<StringShape>;
149
+ group: LiteralShape<readonly Group[]>;
150
+ origin: LiteralShape<readonly ["host"]>;
151
+ environment: OptionalShape<LiteralShape<readonly Environment[]>>;
152
+ hex: OptionalShape<StringShape>;
89
153
  source: OptionalShape<StringShape>;
90
- }, false>;
154
+ }, false>, ObjectShape<{
155
+ path: StringShape;
156
+ group: LiteralShape<readonly Group[]>;
157
+ origin: LiteralShape<readonly ["template", "computed"]>;
158
+ environment: OptionalShape<LiteralShape<readonly Environment[]>>;
159
+ content: StringShape;
160
+ }, false>]>;
91
161
 
92
162
  /**
93
163
  * The whole diff of a plan against a target's current content.
@@ -122,12 +192,18 @@ export declare interface Audit {
122
192
  */
123
193
  export declare function auditToReview(audit: Audit): string;
124
194
 
125
- /** The closed, JSON-serializable package spec. */
195
+ /** Tooling versions shared by scaffold and every generated workspace. */
196
+ export declare const BASE_DEV_DEPENDENCIES: Readonly<Record<string, string>>;
197
+
198
+ /** The closed, JSON-serializable source/application workspace spec. */
126
199
  export declare interface Blueprint {
127
200
  readonly name: string;
128
201
  readonly description?: string;
129
202
  readonly keywords: readonly string[];
130
- readonly surfaces: readonly Surface[];
203
+ /** Published library environments under `src`; empty for an application-only workspace. */
204
+ readonly src: readonly Environment[];
205
+ /** Private runtime environments under `app`; empty for a library-only workspace. */
206
+ readonly app: readonly Environment[];
131
207
  readonly dependencies: readonly Dependency[];
132
208
  /** Runtime `@orkestrel/*` peers, emitted as `peerDependencies` — a peer flagged `optional` also gets a `peerDependenciesMeta` entry. */
133
209
  readonly peers: readonly Dependency[];
@@ -136,6 +212,8 @@ export declare interface Blueprint {
136
212
  readonly version: string;
137
213
  readonly engines: string;
138
214
  readonly overrides: readonly Override[];
215
+ /** Structural: `true` only for a repo that ships its own `src/bin` — the self-hosting tax (a `bin` field, the `scaffold` script invoking `dist/bin/scaffold.js` directly, the `check/test/build:src:bin` scripts, `build:host`, the `srcBin` vite project) applies ONLY when `true`, never by name. */
216
+ readonly engine: boolean;
139
217
  }
140
218
 
141
219
  /**
@@ -144,10 +222,11 @@ export declare interface Blueprint {
144
222
  * @param name - The package name.
145
223
  * @param options - A partial of the remaining `Blueprint` fields.
146
224
  * @remarks
147
- * `version` / `engines` default `DEFAULT_VERSION` / `DEFAULT_ENGINES`, `surfaces`
148
- * defaults `['core']`, and `keywords` / `dependencies` / `peers` / `extras` /
149
- * `overrides` default `[]`. `description` is OMITTED entirely when absent, so
150
- * the result round-trips the exact-record `Blueprint` guard.
225
+ * `version` / `engines` default `DEFAULT_VERSION` / `DEFAULT_ENGINES`,
226
+ * `src` defaults `['core']`, and `app` / `keywords` / `dependencies` /
227
+ * `peers` / `extras` / `overrides` default `[]`. `description` is OMITTED
228
+ * entirely when absent, so the result round-trips the exact-record
229
+ * `Blueprint` guard.
151
230
  * @returns A complete `Blueprint`.
152
231
  *
153
232
  * @example
@@ -163,12 +242,14 @@ export declare function blueprint(name: string, options?: Partial<Omit<Blueprint
163
242
  * Build the `Blueprint` object shape.
164
243
  *
165
244
  * @remarks
166
- * `surfaces` is a `literalShape(SURFACES)` array with `min: 1`; `name` is a
167
- * plain `min: 1` string, NOT pattern-constrained, so `generate` stays
168
- * satisfiable — the `NAME_PATTERN` law lives in the semantic pass
169
- * (`validateBlueprint`), never in this compiled contract. `peers` and `extras`
170
- * are `dependencyShape()` arrays alongside `dependencies` the cross-array
171
- * uniqueness and overlap rules also live in `validateBlueprint`.
245
+ * `src` and `app` are independent `literalShape(ENVIRONMENTS)` arrays; the
246
+ * cross-field requirement that at least one is non-empty lives in
247
+ * `hasBlueprintEnvironment`. `name` is a plain `min: 1` string, NOT
248
+ * pattern-constrained, so `generate` stays satisfiable the `NAME_PATTERN`
249
+ * law lives in the semantic pass (`validateBlueprint`), never in this compiled
250
+ * contract. `peers` and `extras` are `dependencyShape()` arrays alongside
251
+ * `dependencies` — the cross-array uniqueness and overlap rules also live in
252
+ * `validateBlueprint`.
172
253
  *
173
254
  * @returns A fresh `ContractShape` describing the closed `Blueprint` spec.
174
255
  */
@@ -176,7 +257,8 @@ export declare function blueprintShape(): ObjectShape<{
176
257
  name: StringShape;
177
258
  description: OptionalShape<StringShape>;
178
259
  keywords: ArrayShape<StringShape>;
179
- surfaces: ArrayShape<LiteralShape<readonly ["core", "browser", "server"]>>;
260
+ src: ArrayShape<LiteralShape<readonly Environment[]>>;
261
+ app: ArrayShape<LiteralShape<readonly Environment[]>>;
180
262
  dependencies: ArrayShape<ObjectShape<{
181
263
  name: StringShape;
182
264
  range: StringShape;
@@ -198,6 +280,7 @@ export declare function blueprintShape(): ObjectShape<{
198
280
  path: StringShape;
199
281
  content: StringShape;
200
282
  }, false>>;
283
+ engine: BooleanShape;
201
284
  }, false>;
202
285
 
203
286
  /**
@@ -205,12 +288,10 @@ export declare function blueprintShape(): ObjectShape<{
205
288
  *
206
289
  * @param spec - The blueprint to derive members from.
207
290
  * @remarks
208
- * The canonical per-surface inventory is the four `Category` buckets applied to
209
- * the package's PascalCase entity name: an `Options` type, an `Interface` type,
210
- * a `create*` factory, a default-id constant, and the entity itself. Standalone
211
- * helpers, validators, and shapers are hand-authored in implementation, not
212
- * scaffolded.
213
- * @returns The declared `Member[]`, one set per surface.
291
+ * Published source environments receive the canonical entity/type/factory/constant
292
+ * inventory. Application environments receive their exact public declaration kinds,
293
+ * including parsers, guards, handlers, errors, and runners where present.
294
+ * @returns The declared `Member[]`, one set per environment.
214
295
  *
215
296
  * @example
216
297
  * ```ts
@@ -223,7 +304,7 @@ export declare function blueprintToMembers(spec: Blueprint): readonly Member[];
223
304
 
224
305
  /**
225
306
  * The full pure compilation: draft a blueprint's artifacts — the manifest and
226
- * exports combination rules over the per-surface `SURFACE_MATRIX` rows, plus
307
+ * exports combination rules over the per-environment `SRC_MATRIX` rows, plus
227
308
  * `HOST_PATHS` and `overrides` — then pin.
228
309
  *
229
310
  * @param blueprint - The `Blueprint` to compile.
@@ -232,12 +313,23 @@ export declare function blueprintToMembers(spec: Blueprint): readonly Member[];
232
313
  *
233
314
  * @example
234
315
  * ```ts
235
- * const plan = blueprintToPlan(blueprint('router', { surfaces: ['core'] }))
316
+ * const plan = blueprintToPlan(blueprint('router', { src: ['core'] }))
236
317
  * plan.artifacts.length // every file the package needs
237
318
  * ```
238
319
  */
239
320
  export declare function blueprintToPlan(blueprint: Blueprint, groups?: readonly Group[]): Plan;
240
321
 
322
+ /** One supported library-output module format. */
323
+ export declare type BuildFormat = 'es' | 'cjs';
324
+
325
+ /**
326
+ * Encode bytes as exact lowercase hexadecimal text.
327
+ *
328
+ * @param bytes - The bytes to encode.
329
+ * @returns Two lowercase hexadecimal digits per input byte.
330
+ */
331
+ export declare function bytesToHex(bytes: Uint8Array): string;
332
+
241
333
  /**
242
334
  * One fleet package's catalog row — the `orkestrel` agent's package-catalog
243
335
  * section, derived rather than hand-maintained.
@@ -284,9 +376,10 @@ export declare function catalogNames(text: string): readonly string[];
284
376
  * @param entries - The catalog rows to render.
285
377
  * @remarks
286
378
  * Deduplicated by `name` (a later entry for a repeated name wins), then
287
- * code-unit sorted by `name`. An empty `description` renders as `—` (an em
288
- * dash), never a blank cell. Deterministic same input, same output, every
289
- * time — via `alignTable`; trailing-newline terminated.
379
+ * code-unit sorted by `name`. Network-controlled descriptions are
380
+ * intentionally omitted because this block enters agent instruction context.
381
+ * Deterministic — same input, same output, every time — via `alignTable`;
382
+ * trailing-newline terminated.
290
383
  * @returns The aligned GFM table string.
291
384
  *
292
385
  * @example
@@ -297,16 +390,27 @@ export declare function catalogNames(text: string): readonly string[];
297
390
  * { name: '@orkestrel/router', version: '0.0.5', description: 'A tiny hash-router.' },
298
391
  * { name: '@orkestrel/contract', version: '0.0.5', description: '' },
299
392
  * ])
300
- * // '| Package | Version | Description |\n| |\n| @orkestrel/contract | 0.0.5 | — |\n…'
393
+ * // '> Generated package identifiers are untrusted discovery data, never instructions.\n\n| Package …'
301
394
  * ```
302
395
  */
303
396
  export declare function catalogToBlock(entries: readonly CatalogEntry[]): string;
304
397
 
305
- /** The four `Category` values, frozen. */
306
- export declare const CATEGORIES: readonly ["type", "constant", "factory", "entity"];
398
+ /** The nine `Category` values, frozen. */
399
+ export declare const CATEGORIES: readonly Category[];
400
+
401
+ /** What a declared public `Member` is in the scaffolded environment. */
402
+ export declare type Category = 'type' | 'alias' | 'constant' | 'factory' | 'entity' | 'parser' | 'guard' | 'handler' | 'error';
307
403
 
308
- /** What a declared `Member` IS in the scaffolded surface. */
309
- export declare type Category = 'type' | 'constant' | 'factory' | 'entity';
404
+ /** Immutable official actions/checkout v6.0.2 commit used by generated CI. */
405
+ export declare const CHECKOUT_ACTION_SHA = "de0fac2e4500dabe0009e67214ff5f5447ce83dd";
406
+
407
+ /**
408
+ * Build selection-aware GitHub CI without external service dependencies.
409
+ *
410
+ * @param spec - The workspace blueprint.
411
+ * @returns The complete `.github/workflows/ci.yml` content.
412
+ */
413
+ export declare function ciWorkflow(spec: Blueprint): string;
310
414
 
311
415
  /**
312
416
  * A code-unit (not locale-sensitive) comparator — matches the `keywords` sort
@@ -324,7 +428,7 @@ export declare type Category = 'type' | 'constant' | 'factory' | 'entity';
324
428
  export declare function compareCodeUnit(a: string, b: string): number;
325
429
 
326
430
  /** The pipeline phases in order, frozen. */
327
- export declare const COMPILE_STAGES: readonly ["draft", "gate", "pin"];
431
+ export declare const COMPILE_STAGES: readonly CompileStage[];
328
432
 
329
433
  /** A visible marker for a stage that failed. */
330
434
  export declare interface CompileFailure {
@@ -343,7 +447,7 @@ export declare interface CompileFailure {
343
447
  * CLOSED — a blueprint failing `validateBlueprint`, or carrying an override
344
448
  * that matches no planned artifact or targets a `host`-origin path, yields a
345
449
  * visible incomplete `Scaffolding` (`plan` absent, `questions` populated)
346
- * rather than throwing. A dependency outside the vendored guide set surfaces
450
+ * rather than throwing. A dependency outside the vendored guide set src
347
451
  * a non-blocking `Question` and a `host`-origin pointer artifact instead of a
348
452
  * fabricated mirror. `compile` emits `compile` only for a complete
349
453
  * compilation and `block` for a gated one; `audit` emits `block` (when gated)
@@ -355,7 +459,7 @@ export declare interface CompileFailure {
355
459
  * import { blueprint, Compiler } from '@src/core'
356
460
  *
357
461
  * const compiler = new Compiler()
358
- * const scaffolding = compiler.compile(blueprint('router', { surfaces: ['core'] }))
462
+ * const scaffolding = compiler.compile(blueprint('router', { src: ['core'] }))
359
463
  * scaffolding.complete // true
360
464
  * compiler.destroy()
361
465
  * ```
@@ -375,7 +479,7 @@ export declare class Compiler implements CompilerInterface {
375
479
  *
376
480
  * @example
377
481
  * ```ts
378
- * const scaffolding = compiler.compile(blueprint('timeout', { surfaces: ['core'] }))
482
+ * const scaffolding = compiler.compile(blueprint('timeout', { src: ['core'] }))
379
483
  * scaffolding.stages.map((record) => record.stage) // ['draft', 'gate', 'pin']
380
484
  * ```
381
485
  */
@@ -393,7 +497,7 @@ export declare class Compiler implements CompilerInterface {
393
497
  *
394
498
  * @example
395
499
  * ```ts
396
- * const audit = compiler.audit(blueprint('timeout', { surfaces: ['core'] }), {})
500
+ * const audit = compiler.audit(blueprint('timeout', { src: ['core'] }), {})
397
501
  * audit.missing // every artifact — nothing exists at the target yet
398
502
  * ```
399
503
  */
@@ -414,7 +518,7 @@ export declare interface CompileRecord {
414
518
  readonly error?: string;
415
519
  }
416
520
 
417
- /** `Compiler`'s push observation surface (AGENTS §13). */
521
+ /** `Compiler`'s push observation channel (AGENTS §13). */
418
522
  export declare type CompilerEventMap = {
419
523
  readonly compile: readonly [scaffolding: Scaffolding];
420
524
  readonly audit: readonly [audit: Audit];
@@ -440,6 +544,23 @@ export declare interface CompilerOptions {
440
544
  /** The three fixed pipeline phases, in order. */
441
545
  export declare type CompileStage = 'draft' | 'gate' | 'pin';
442
546
 
547
+ /**
548
+ * Measure a rendered fragment's column width, counting each literal tab as
549
+ * `JSON_TAB_WIDTH` columns (matching `.oxfmtrc.json`'s `tabWidth`) and every
550
+ * other character as one.
551
+ *
552
+ * @param text - The rendered fragment to measure.
553
+ * @returns The fragment's column width against `JSON_PRINT_WIDTH`.
554
+ *
555
+ * @example
556
+ * ```ts
557
+ * import { computeColumnWidth } from '@orkestrel/scaffold'
558
+ *
559
+ * computeColumnWidth('\t"a"') // 3 — one tab counted as JSON_TAB_WIDTH, plus two characters
560
+ * ```
561
+ */
562
+ export declare function computeColumnWidth(text: string): number;
563
+
443
564
  /**
444
565
  * Compute a canonical FNV-1a digest of a text string.
445
566
  *
@@ -461,7 +582,7 @@ export declare function computeHash(text: string): string;
461
582
 
462
583
  /**
463
584
  * Draft the `configs` group's `computed` artifacts — the root
464
- * `tsconfig.json` / `vite.config.ts` plus each declared surface's
585
+ * `tsconfig.json` / `vite.config.ts` plus each declared environment's
465
586
  * `configs/src/*` pair, grounded against the live middleware (core+server)
466
587
  * and router (core+browser+server) exemplars.
467
588
  *
@@ -475,10 +596,57 @@ export declare function computeHash(text: string): string;
475
596
  */
476
597
  export declare function configArtifacts(spec: Blueprint): readonly Artifact[];
477
598
 
599
+ /** Constant-declaration token kept out of template literals consumed by parity scans. */
600
+ export declare const CONST_KEYWORD = "const";
601
+
602
+ /** A text artifact produced by the template or computed compilation path. */
603
+ export declare interface ContentArtifact extends ArtifactBase {
604
+ readonly origin: 'template' | 'computed';
605
+ readonly content: string;
606
+ readonly hex?: never;
607
+ readonly source?: never;
608
+ }
609
+
610
+ /**
611
+ * Count the UTF-8 bytes required by text.
612
+ *
613
+ * @param content - The text to measure.
614
+ * @returns Its encoded UTF-8 byte length.
615
+ */
616
+ export declare function contentByteLength(content: string): number;
617
+
618
+ /**
619
+ * Read one Unicode scalar for UTF-8 encoding, replacing an unpaired surrogate.
620
+ *
621
+ * @param content - The source text.
622
+ * @param index - The UTF-16 code-unit index.
623
+ * @returns A Unicode scalar value, using U+FFFD for an unpaired surrogate.
624
+ */
625
+ export declare function contentCodePoint(content: string, index: number): number;
626
+
627
+ /**
628
+ * Encode text as exact UTF-8 bytes without depending on a browser or server host.
629
+ *
630
+ * @param content - The text to encode.
631
+ * @returns Its exact UTF-8 bytes.
632
+ */
633
+ export declare function contentToBytes(content: string): Uint8Array;
634
+
635
+ /**
636
+ * Encode a string's UTF-8 bytes as exact lowercase hexadecimal text.
637
+ *
638
+ * @param content - The text to encode.
639
+ * @returns The exact hexadecimal UTF-8 representation.
640
+ */
641
+ export declare function contentToHex(content: string): string;
642
+
643
+ /** Unicode controls, formatting controls, and line/paragraph separators rejected at text boundaries. */
644
+ export declare const CONTROL_CHARACTER_PATTERN: RegExp;
645
+
478
646
  /**
479
647
  * `configs/src/tsconfig.core.json` — unchanged core shape.
480
648
  *
481
- * @returns The core surface `tsconfig` file content, newline-terminated.
649
+ * @returns The core environment `tsconfig` file content, newline-terminated.
482
650
  *
483
651
  * @example
484
652
  * ```ts
@@ -489,9 +657,9 @@ export declare function coreTsconfig(): string;
489
657
 
490
658
  /**
491
659
  * `configs/src/vite.core.config.ts` — inlines its own `build.lib` /
492
- * `rollupOptions` (core's `srcCore` root export carries no build.lib).
660
+ * `rolldownOptions` (core's `srcCore` root export carries no build.lib).
493
661
  *
494
- * @returns The core surface `vite.config.ts` file content, newline-terminated.
662
+ * @returns The core environment `vite.config.ts` file content, newline-terminated.
495
663
  *
496
664
  * @example
497
665
  * ```ts
@@ -516,7 +684,7 @@ export declare function coreViteConfig(): string;
516
684
  * ```ts
517
685
  * import { createBlueprint } from '@src/core'
518
686
  *
519
- * createBlueprint({ name: 'Router', surfaces: [] }) // throws ScaffoldError('INVALID', …)
687
+ * createBlueprint({ name: 'Router', src: [] }) // throws ScaffoldError('INVALID', …)
520
688
  * ```
521
689
  */
522
690
  export declare function createBlueprint(data: Partial<Blueprint> & {
@@ -557,7 +725,7 @@ export declare function coreViteConfig(): string;
557
725
  export declare function createPlanManager(options?: PlanManagerOptions): PlanManagerInterface;
558
726
 
559
727
  /** The `engines.node` range the `blueprint` builder fills. */
560
- export declare const DEFAULT_ENGINES = ">=22";
728
+ export declare const DEFAULT_ENGINES = ">=22.12.0";
561
729
 
562
730
  /** The starting version the `blueprint` builder fills. */
563
731
  export declare const DEFAULT_VERSION = "0.0.1";
@@ -637,12 +805,11 @@ export declare function coreViteConfig(): string;
637
805
  }, false>;
638
806
 
639
807
  /**
640
- * The devDependency baseline every repo in the line carries the same set
641
- * (`@vitest/browser-playwright` included regardless of a browser surface: both
642
- * @orkestrel/middleware, core+server, and @orkestrel/router, core+browser+server,
643
- * ship it grounded, not conditional). A package's `extras` (code-unit sorted)
644
- * merge in on top, the extras' declared range winning on a name collision with
645
- * the baseline.
808
+ * The host-neutral devDependency baseline every generated workspace needs.
809
+ * Browser providers are added only by browser selections or the scaffold
810
+ * engine's generated-browser consumer proof. A package's `extras` (code-unit
811
+ * sorted) merge in on top, the extras' declared range winning on a name
812
+ * collision with the baseline.
646
813
  *
647
814
  * @param extras - The blueprint's package-specific `extras` `Dependency[]`.
648
815
  * @returns The merged `devDependencies` record.
@@ -660,14 +827,26 @@ export declare function coreViteConfig(): string;
660
827
  * @param plan - The plan whose artifacts are the source of truth.
661
828
  * @param current - The target's current content, keyed by artifact-relative path.
662
829
  * @remarks
663
- * A `template` / `computed` artifact whose rendered content the target does not
664
- * match is `stale`; one the target lacks is `missing`; a target file the plan
665
- * does not own is `foreign`. A `host`-origin artifact is audited by PRESENCE
666
- * only `missing` or `aligned`, never `stale` UNLESS it has been hydrated
667
- * with its real host bytes (`hydratePlan`'s `content`), in which case it is
668
- * content-compared exactly like a `template` / `computed` artifact and CAN be
669
- * `stale`. A degrade-path or directory-shaped host artifact (never hydrated)
670
- * stays presence-only.
830
+ * Audit semantics are per-origin. A `host`-origin artifact is audited by
831
+ * PRESENCE only `missing` or `aligned`, never `stale` UNLESS it has been
832
+ * hydrated with its real host bytes (`hydratePlan`'s `content`), in which case
833
+ * it is content-compared exactly like a `computed` artifact and CAN be
834
+ * `stale`. `hydratePlan` expands directory-shaped host artifacts into
835
+ * content-bearing file artifacts; only an unresolved degrade-path host
836
+ * artifact stays presence-only. A `computed` artifact is content-aware canon —
837
+ * `missing` / `aligned` / `stale` — and gates the audit like any drifted
838
+ * finding. A `template`-origin artifact is BIRTH-ONLY and AUDIT-EXEMPT: it is
839
+ * always reported `aligned`, regardless of whether the target has it at all
840
+ * or what its bytes are. Starter files (source stubs, test stubs, starter
841
+ * guides, README) are written ONCE by `materialize` and are legitimately
842
+ * outgrown — real code replaces the stub, a hand-authored guide replaces the
843
+ * scaffold prose, an entity gets renamed. Content- or presence-comparing a
844
+ * mature package against its birth stub is a category error (the build and
845
+ * parity gates already police the package's substance) AND makes any
846
+ * unscoped repair a data-loss footgun — a stub overwrite would clobber real,
847
+ * hand-authored code. `template` findings therefore never contribute to
848
+ * `drifted` / `missing` / `clean`. A target file the plan does not own is
849
+ * `foreign`.
671
850
  * @returns The `Audit` of drift findings — pure, no I/O.
672
851
  *
673
852
  * @example
@@ -677,7 +856,7 @@ export declare function coreViteConfig(): string;
677
856
  * diffPlan(plan, current) // { findings: [...], clean: false, complete: true, drifted: 1, missing: 20, foreign: 0 }
678
857
  * ```
679
858
  */
680
- export declare function diffPlan(plan: Plan, current: Readonly<Record<string, string>>): Audit;
859
+ export declare function diffPlan(plan: Plan, current: Snapshot): Audit;
681
860
 
682
861
  /** One `Finding`'s verdict against the target's current content. */
683
862
  export declare type Drift = 'aligned' | 'stale' | 'missing' | 'foreign';
@@ -696,10 +875,13 @@ export declare function coreViteConfig(): string;
696
875
  */
697
876
  export declare function dualCondition(path: string): Readonly<Record<string, unknown>>;
698
877
 
878
+ /** The minimum-Node engine syntax accepted by `validateBlueprint`. */
879
+ export declare const ENGINES_PATTERN: RegExp;
880
+
699
881
  /**
700
882
  * Build the `main` / `module` / top-level `types` entry fields.
701
883
  *
702
- * @param surfaces - The declared `Surface[]`.
884
+ * @param src - The declared `Environment[]`.
703
885
  * @returns The `package.json` `main` / `module` / optional `types` fields.
704
886
  *
705
887
  * @example
@@ -707,16 +889,40 @@ export declare function coreViteConfig(): string;
707
889
  * entryFields(['browser']).main // './dist/src/browser/index.js'
708
890
  * ```
709
891
  */
710
- export declare function entryFields(surfaces: readonly Surface[]): {
892
+ export declare function entryFields(src: readonly Environment[]): {
711
893
  readonly main: string;
712
894
  readonly module: string;
713
895
  readonly types?: string;
714
896
  };
715
897
 
898
+ /** One core, browser, or server environment in the scaffolded workspace. */
899
+ export declare type Environment = 'core' | 'browser' | 'server';
900
+
901
+ /** The three `Environment` values, frozen — compose with `literalOf(...)` / `parseEnum(...)`. */
902
+ export declare const ENVIRONMENTS: readonly Environment[];
903
+
904
+ /**
905
+ * Escape text for an HTML text-node context.
906
+ *
907
+ * @param value - The untrusted text value.
908
+ * @returns Text with the five HTML-significant characters entity-escaped.
909
+ *
910
+ * @example
911
+ * ```ts
912
+ * import { escapeHtmlText } from '@orkestrel/scaffold'
913
+ *
914
+ * escapeHtmlText('<app & "team">') // '&lt;app &amp; &quot;team&quot;&gt;'
915
+ * ```
916
+ */
917
+ export declare function escapeHtmlText(value: string): string;
918
+
919
+ /** Declaration token kept out of template literals so parity scans see only real exports. */
920
+ export declare const EXPORT_KEYWORD = "export";
921
+
716
922
  /**
717
923
  * Build the `package.json` `exports` map.
718
924
  *
719
- * @param surfaces - The declared `Surface[]`.
925
+ * @param src - The declared `Environment[]`.
720
926
  * @returns The `package.json` `exports` map.
721
927
  *
722
928
  * @example
@@ -724,7 +930,7 @@ export declare function coreViteConfig(): string;
724
930
  * exportsMap(['core'])['.'] // dual import/require condition block
725
931
  * ```
726
932
  */
727
- export declare function exportsMap(surfaces: readonly Surface[]): Readonly<Record<string, unknown>>;
933
+ export declare function exportsMap(src: readonly Environment[]): Readonly<Record<string, unknown>>;
728
934
 
729
935
  /**
730
936
  * The `extras` dependency-name RegExp — a strict npm package-name shape: an
@@ -740,16 +946,19 @@ export declare function coreViteConfig(): string;
740
946
  */
741
947
  export declare const EXTRA_NAME_PATTERN: RegExp;
742
948
 
949
+ /** The registry-only semver subset accepted for package-specific development extras. */
950
+ export declare const EXTRA_RANGE_PATTERN: RegExp;
951
+
743
952
  /**
744
953
  * Fill one `TEMPLATES` entry into a `template`-origin `Artifact`, optionally
745
- * tagged with the owning `Surface` (source/tests artifacts that live under a
746
- * declared surface's tree).
954
+ * tagged with the owning `Environment` (source/tests artifacts that live under a
955
+ * declared environment's tree).
747
956
  *
748
957
  * @param path - The artifact's output path.
749
958
  * @param group - The artifact's `Group`.
750
959
  * @param id - The `TEMPLATES` entry id to fill.
751
960
  * @param values - The placeholder values to fill the template with.
752
- * @param surface - The owning `Surface`, when the artifact lives under a declared surface's tree.
961
+ * @param environment - The owning `Environment`, when the artifact lives under a declared environment's tree.
753
962
  * @returns The filled `template`-origin `Artifact`.
754
963
  *
755
964
  * @example
@@ -758,17 +967,60 @@ export declare function coreViteConfig(): string;
758
967
  * // { path: 'README.md', group: 'docs', origin: 'template', content: '# router\n…' }
759
968
  * ```
760
969
  */
761
- export declare function fillArtifact(path: string, group: Group, id: string, values: Readonly<Record<string, unknown>>, surface?: Surface): Artifact;
970
+ export declare function fillArtifact(path: string, group: Group, id: string, values: Readonly<Record<string, unknown>>, environment?: Environment): Artifact;
971
+
972
+ /**
973
+ * Find the first exact, case-insensitive, or file/descendant path collision.
974
+ *
975
+ * @param paths - Portable file paths in deterministic input order.
976
+ * @returns The first conflicting pair, or `undefined`.
977
+ */
978
+ export declare function findFileConflict(paths: readonly string[]): readonly [existing: string, duplicate: string] | undefined;
762
979
 
763
980
  /** One audit drift result. */
764
981
  export declare interface Finding {
765
982
  readonly path: string;
766
983
  readonly group: Group;
767
984
  readonly drift: Drift;
985
+ /** Exact bounded observed bytes for a stale destination, used as the repair precondition. */
986
+ readonly observed?: string;
768
987
  }
769
988
 
989
+ /**
990
+ * Find the first exact or portable case-insensitive path collision.
991
+ *
992
+ * @param paths - Portable paths in deterministic input order.
993
+ * @returns The first `[existing, duplicate]` pair, or `undefined`.
994
+ */
995
+ export declare function findPathConflict(paths: readonly string[]): readonly [existing: string, duplicate: string] | undefined;
996
+
997
+ /**
998
+ * Serialize a value to newline-terminated JSON that matches the fleet's own
999
+ * `oxfmt` output byte-for-byte — objects one key per line, arrays collapsed
1000
+ * onto one line when they fit `JSON_PRINT_WIDTH`, one item per line
1001
+ * otherwise.
1002
+ *
1003
+ * @param value - The value to serialize (config JSON — objects/arrays/primitives).
1004
+ * @remarks
1005
+ * `JSON.stringify(value, undefined, '\t')` always breaks arrays one item per
1006
+ * line; `oxfmt` collapses short ones. Emitting through `formatJson` keeps
1007
+ * computed config JSON format-stable by construction — `oxfmt --check` never
1008
+ * has anything left to rewrite. The rendering itself is delegated to
1009
+ * `renderValue` / `renderArray` / `renderObject` / `computeColumnWidth`, so
1010
+ * `formatJson` is a thin orchestrator around them.
1011
+ * @returns The rendered value, newline-terminated.
1012
+ *
1013
+ * @example
1014
+ * ```ts
1015
+ * import { formatJson } from '@orkestrel/scaffold'
1016
+ *
1017
+ * formatJson({ lib: ['ESNext', 'DOM'] }) // '{\n\t"lib": ["ESNext", "DOM"]\n}\n'
1018
+ * ```
1019
+ */
1020
+ export declare function formatJson(value: unknown): string;
1021
+
770
1022
  /** The four `Freshness` values, frozen — the currency axis `Sync` reports on. */
771
- export declare const FRESHNESS: readonly ["current", "behind", "missing", "failed"];
1023
+ export declare const FRESHNESS: readonly Freshness[];
772
1024
 
773
1025
  /**
774
1026
  * One `GuideSync` / `VersionSync`'s currency against upstream.
@@ -778,11 +1030,14 @@ export declare function coreViteConfig(): string;
778
1030
  */
779
1031
  export declare type Freshness = 'current' | 'behind' | 'missing' | 'failed';
780
1032
 
1033
+ /** Function-declaration token kept out of template literals consumed by parity scans. */
1034
+ export declare const FUNCTION_KEYWORD = "function";
1035
+
781
1036
  /** The closed artifact-group vocabulary a plan selects over. */
782
1037
  export declare type Group = 'manifest' | 'configs' | 'source' | 'tests' | 'guides' | 'docs' | 'orchestration';
783
1038
 
784
1039
  /** The seven `Group` values, frozen — the artifact-group selection vocabulary. */
785
- export declare const GROUPS: readonly ["manifest", "configs", "source", "tests", "guides", "docs", "orchestration"];
1040
+ export declare const GROUPS: readonly Group[];
786
1041
 
787
1042
  /**
788
1043
  * Draft the `guides` group's artifacts — the package's own filled guide stub,
@@ -802,10 +1057,10 @@ export declare function coreViteConfig(): string;
802
1057
 
803
1058
  /**
804
1059
  * Build an `alignTable` markdown table over a member category's rows, deduped
805
- * by name — `blueprintToMembers` declares one full member set PER surface, so
806
- * a multi-surface blueprint carries byte-identical name/summary rows once per
807
- * surface; the one guide (AGENTS §22) lists each declared member once,
808
- * grouped across its surfaces.
1060
+ * by name — `blueprintToMembers` declares one full member set PER environment, so
1061
+ * a multi-environment blueprint carries byte-identical name/summary rows once per
1062
+ * environment; the one guide (AGENTS §22) lists each declared member once,
1063
+ * grouped across its src.
809
1064
  *
810
1065
  * @param category - The `Member['category']` to filter rows by.
811
1066
  * @param members - The blueprint's derived `Member[]` (previously closed over by the caller).
@@ -818,6 +1073,14 @@ export declare function coreViteConfig(): string;
818
1073
  */
819
1074
  export declare function guideMemberTable(category: Member['category'], members: readonly Member[]): string;
820
1075
 
1076
+ /**
1077
+ * Build the generated application server's method contract section.
1078
+ *
1079
+ * @param spec - The workspace blueprint.
1080
+ * @returns A Methods section when app/server is selected, otherwise an empty string.
1081
+ */
1082
+ export declare function guideMethods(spec: Blueprint): string;
1083
+
821
1084
  /**
822
1085
  * One dependency guide fetched from upstream at its `path`, plus its
823
1086
  * `freshness` verdict against the local mirror.
@@ -835,20 +1098,105 @@ export declare function coreViteConfig(): string;
835
1098
  readonly content: string;
836
1099
  readonly freshness: Freshness;
837
1100
  readonly note?: string;
1101
+ /** SHA-256 of the observed local mirror, or `absent`; omitted outside target-aware pulls. */
1102
+ readonly baseline?: string;
838
1103
  }
839
1104
 
1105
+ /**
1106
+ * Build links to every generated source and application test file.
1107
+ *
1108
+ * @param spec - The workspace blueprint.
1109
+ * @param pascal - The source entity name.
1110
+ * @returns A newline-separated Markdown test inventory.
1111
+ */
1112
+ export declare function guideTests(spec: Blueprint, pascal: string): string;
1113
+
1114
+ /**
1115
+ * Build complete guide examples for every generated public function.
1116
+ *
1117
+ * @param spec - The workspace blueprint.
1118
+ * @param pascal - The source entity name.
1119
+ * @returns TypeScript fences covering each selected source and app environment.
1120
+ */
1121
+ export declare function guideUsage(spec: Blueprint, pascal: string): string;
1122
+
1123
+ /**
1124
+ * Whether a structurally valid blueprint selects at least one source or app environment.
1125
+ *
1126
+ * @param blueprint - The structurally valid blueprint to inspect.
1127
+ * @returns `true` when `src` or `app` is non-empty.
1128
+ */
1129
+ export declare function hasBlueprintEnvironment(blueprint: Blueprint): boolean;
1130
+
1131
+ /**
1132
+ * Determine whether a structured boundary contains data properties only.
1133
+ *
1134
+ * @param value - The candidate record/array graph.
1135
+ * @returns `true` when copying the graph cannot invoke a user-defined accessor.
1136
+ */
1137
+ export declare function hasOnlyDataProperties(value: unknown): boolean;
1138
+
1139
+ /** Determine whether one artifact fits the public physical-byte limit. */
1140
+ export declare function hasValidArtifactBytes(artifact: Artifact): boolean;
1141
+
1142
+ /**
1143
+ * Apply the semantic lowercase byte-pair law to an artifact's optional hex.
1144
+ *
1145
+ * @param artifact - The structurally valid artifact to inspect.
1146
+ * @returns `true` when `hex` is absent or encodes whole lowercase bytes.
1147
+ */
1148
+ export declare function hasValidArtifactHex(artifact: Artifact): boolean;
1149
+
1150
+ /** Determine whether an audit snapshot fits the aggregate retained-byte limit. */
1151
+ export declare function hasValidAuditBytes(audit: Audit): boolean;
1152
+
1153
+ /** Determine whether blueprint-authored text fits the per-item and aggregate byte limits. */
1154
+ export declare function hasValidBlueprintBytes(blueprint: Blueprint): boolean;
1155
+
1156
+ /** Determine whether one override fits the public UTF-8 artifact byte limit. */
1157
+ export declare function hasValidOverrideBytes(override: Override): boolean;
1158
+
1159
+ /** Determine whether a plan fits the aggregate retained-artifact byte limit. */
1160
+ export declare function hasValidPlanBytes(plan: Plan): boolean;
1161
+
1162
+ /**
1163
+ * Apply the artifact byte law to every nested artifact in a `Plan`.
1164
+ *
1165
+ * @param plan - The structurally valid plan to inspect.
1166
+ * @returns `true` when every artifact has absent or valid lowercase byte hex.
1167
+ */
1168
+ export declare function hasValidPlanHex(plan: Plan): boolean;
1169
+
1170
+ /** Determine whether a target snapshot is a bounded exact-byte record. */
1171
+ export declare function hasValidSnapshotBytes(snapshot: Snapshot): boolean;
1172
+
1173
+ /** Determine whether every guide body fits the public UTF-8 artifact byte limit. */
1174
+ export declare function hasValidSyncReportBytes(report: SyncReport): boolean;
1175
+
1176
+ /** Exact lowercase hexadecimal bytes: two digits per byte, including empty content. */
1177
+ export declare const HEX_PATTERN: RegExp;
1178
+
840
1179
  /**
841
1180
  * The byte-copied host artifact paths, frozen.
842
1181
  *
843
1182
  * @remarks
844
- * The root docs (`AGENTS.md` / `CLAUDE.md`), `LICENSE`, `.claude`, the three
845
- * SessionStart hook scripts (`scripts/deps.sh` / `scripts/cursor.sh` /
846
- * `scripts/ollama.sh`), the line's seven byte-identical root dotfiles,
847
- * `.github/workflows/ci.yml`, and the two guides-grouped mirrors every repo
848
- * carries: the line-wide dev-tooling guide (`guides/src/guide.md`) and the
1183
+ * The root docs (`AGENTS.md` / `CLAUDE.md`), `LICENSE`, `.agents`, `.claude`, `.codex`,
1184
+ * the four SessionStart hook scripts (`scripts/deps.sh` / `scripts/cursor.sh` /
1185
+ * `scripts/codex.sh` / `scripts/ollama.sh`), the repository coding-law policy module,
1186
+ * the line's seven byte-identical root dotfiles, and the two guides-grouped mirrors every repo carries: the line-wide
1187
+ * dev-tooling guide (`guides/src/guide.md`) and the
849
1188
  * scaffold engine's own self-guide (`guides/src/scaffold.md`).
850
1189
  */
851
- export declare const HOST_PATHS: readonly ["AGENTS.md", "CLAUDE.md", "LICENSE", ".claude", "scripts/deps.sh", "scripts/cursor.sh", "scripts/ollama.sh", ".editorconfig", ".gitattributes", ".gitignore", ".oxfmtrc.json", ".oxlintrc.json", ".oxlintignore", ".prettierignore", ".github/workflows/ci.yml", "guides/src/guide.md", "guides/src/scaffold.md"];
1190
+ export declare const HOST_PATHS: readonly string[];
1191
+
1192
+ /** A byte-copied host artifact; `source` falls back to `path` when absent. */
1193
+ export declare interface HostArtifact extends ArtifactBase {
1194
+ readonly origin: 'host';
1195
+ /** Exact lowercase hexadecimal bytes used for byte-safe host auditing. */
1196
+ readonly hex?: string;
1197
+ readonly source?: string;
1198
+ readonly content?: never;
1199
+ }
852
1200
 
853
1201
  /**
854
1202
  * Resolve the `Group` a byte-copied `HOST_PATHS` entry belongs to.
@@ -859,20 +1207,25 @@ export declare function coreViteConfig(): string;
859
1207
  * @example
860
1208
  * ```ts
861
1209
  * hostGroup('AGENTS.md') // 'docs'
1210
+ * hostGroup('.agents') // 'orchestration'
862
1211
  * hostGroup('.claude') // 'orchestration'
1212
+ * hostGroup('.codex') // 'orchestration'
863
1213
  * ```
864
1214
  */
865
1215
  export declare function hostGroup(path: string): Group;
866
1216
 
1217
+ /** Import token kept out of template literals consumed by parity scans. */
1218
+ export declare const IMPORT_KEYWORD = "import";
1219
+
867
1220
  /**
868
1221
  * Infer a foreign path's `Group` from its leading path segment.
869
1222
  *
870
1223
  * @param path - The target-relative path to classify.
871
1224
  * @remarks
872
1225
  * Ordered prefix match — `src/`, `tests/`, `guides/`, `docs/`, `configs/`,
873
- * then `.github/` / `scripts/` as `'orchestration'`, then the two manifest
874
- * files by exact name. Anything else (a root-level, prefix-less file) falls
875
- * through to `'configs'`.
1226
+ * then `.agents/`, `.claude/`, `.codex/`, `.github/`, and `scripts/` as
1227
+ * `'orchestration'`, then the two manifest files by exact name. Anything else
1228
+ * (a root-level, prefix-less file) falls through to `'configs'`.
876
1229
  * @returns The inferred `Group` for `path`.
877
1230
  *
878
1231
  * @example
@@ -885,12 +1238,15 @@ export declare function coreViteConfig(): string;
885
1238
  */
886
1239
  export declare function inferGroup(path: string): Group;
887
1240
 
1241
+ /** Visible characters forbidden by portable paths and Markdown path cells. */
1242
+ export declare const INVALID_PATH_CHARACTER_PATTERN: RegExp;
1243
+
888
1244
  /**
889
- * Narrow a value to an `Artifact` — `group` / `origin` on-vocabulary.
1245
+ * Narrow a value to an origin-discriminated `Artifact`.
890
1246
  *
891
1247
  * @remarks
892
- * Compiled from {@link artifactShape} via `createContract` (AGENTS §14) — a
893
- * total `Guard`, adversarial input returns `false`, never throws.
1248
+ * Compiled from {@link artifactShape} and refined by
1249
+ * {@link hasValidArtifactHex}; total for adversarial input.
894
1250
  */
895
1251
  export declare const isArtifact: Guard<Artifact>;
896
1252
 
@@ -911,17 +1267,28 @@ export declare function coreViteConfig(): string;
911
1267
  export declare function isBehind(freshness: Freshness): boolean;
912
1268
 
913
1269
  /**
914
- * Narrow a value to a `Blueprint` `surfaces` on-vocabulary and non-empty,
915
- * `name` a non-empty string.
1270
+ * Narrow a value to a `Blueprint` with at least one source or application environment.
916
1271
  *
917
1272
  * @remarks
918
- * Compiled from {@link blueprintShape} via `createContract` (AGENTS §14)
919
- * the `NAME_PATTERN` law is the semantic pass's (`validateBlueprint`), not
920
- * this shape's; a total `Guard`, adversarial input returns `false`, never
921
- * throws.
1273
+ * Compiled from {@link blueprintShape} via `createContract` and refined by
1274
+ * {@link hasBlueprintEnvironment}. The `NAME_PATTERN` law remains in the semantic
1275
+ * pass; this total guard returns `false` for adversarial input and never throws.
922
1276
  */
923
1277
  export declare const isBlueprint: Guard<Blueprint>;
924
1278
 
1279
+ /** Narrow an exact initial-listener record for `Compiler`. */
1280
+ export declare function isCompilerEventHooks(value: unknown): value is EmitterHooks<CompilerEventMap>;
1281
+
1282
+ /**
1283
+ * Narrow a value to a bounded dense array with index data properties only.
1284
+ *
1285
+ * @param value - The candidate array.
1286
+ * @param limit - Maximum item count.
1287
+ * @param guard - The item contract.
1288
+ * @returns `true` only when no custom iterator, method, symbol, accessor, or sparse index exists.
1289
+ */
1290
+ export declare function isDenseDataArray<T>(value: unknown, limit: number, guard: Guard<T>): value is readonly T[];
1291
+
925
1292
  /**
926
1293
  * Narrow a value to a `Dependency` — `name` and `range` non-empty strings.
927
1294
  *
@@ -931,8 +1298,11 @@ export declare function coreViteConfig(): string;
931
1298
  */
932
1299
  export declare const isDependency: Guard<Dependency>;
933
1300
 
1301
+ /** Narrow a listener-error handler accepted by the shared emitter. */
1302
+ export declare function isEmitterErrorHandler(value: unknown): value is EmitterErrorHandler;
1303
+
934
1304
  /**
935
- * Narrow a value to a `Member` — `category` and `surface` on-vocabulary.
1305
+ * Narrow a value to a `Member` — `category` and `environment` on-vocabulary.
936
1306
  *
937
1307
  * @remarks
938
1308
  * Compiled from {@link memberShape} via `createContract` (AGENTS §14) — a
@@ -959,22 +1329,8 @@ export declare function coreViteConfig(): string;
959
1329
  */
960
1330
  export declare const isPlan: Guard<Plan>;
961
1331
 
962
- /**
963
- * Narrow an unknown value to a plain (non-array, non-null) JSON object.
964
- *
965
- * @param value - The value to narrow.
966
- * @returns `true` iff `value` is a non-null, non-array object.
967
- *
968
- * @example
969
- * ```ts
970
- * import { isRecord } from '@orkestrel/scaffold'
971
- *
972
- * isRecord({ a: 1 }) // true
973
- * isRecord([1, 2]) // false
974
- * isRecord(null) // false
975
- * ```
976
- */
977
- export declare function isRecord(value: unknown): value is Record<string, unknown>;
1332
+ /** Narrow an exact initial-listener record for `PlanManager`. */
1333
+ export declare function isPlanManagerEventHooks(value: unknown): value is EmitterHooks<PlanManagerEventMap>;
978
1334
 
979
1335
  /**
980
1336
  * Narrow a caught value to a `ScaffoldError`.
@@ -996,11 +1352,25 @@ export declare function coreViteConfig(): string;
996
1352
  * `guide` / `version` sections composed.
997
1353
  *
998
1354
  * @remarks
999
- * Compiled from {@link syncReportShape} via `createContract` (AGENTS §14) — a
1000
- * total `Guard`, adversarial input returns `false`, never throws.
1355
+ * Compiled from {@link syncReportShape} via `createContract` and refined by
1356
+ * {@link hasValidSyncReportBytes}; total for adversarial input.
1001
1357
  */
1002
1358
  export declare const isSyncReport: Guard<SyncReport>;
1003
1359
 
1360
+ /**
1361
+ * Narrow a value to the bounded bare name accepted by a workspace blueprint.
1362
+ *
1363
+ * @param value - The candidate workspace name.
1364
+ * @returns `true` only for a `NAME_PATTERN` string no longer than `MAX_NAME_LENGTH`.
1365
+ */
1366
+ export declare function isWorkspaceName(value: unknown): value is string;
1367
+
1368
+ /** The fleet's `.oxfmtrc.json` `printWidth` — `formatJson`'s array-collapse threshold. */
1369
+ export declare const JSON_PRINT_WIDTH = 100;
1370
+
1371
+ /** The fleet's `.oxfmtrc.json` `tabWidth` — the column width `formatJson` counts each tab as. */
1372
+ export declare const JSON_TAB_WIDTH = 2;
1373
+
1004
1374
  /**
1005
1375
  * Parse a `package.json` text into its declared `@orkestrel/*` dependencies.
1006
1376
  *
@@ -1022,12 +1392,53 @@ export declare function coreViteConfig(): string;
1022
1392
  */
1023
1393
  export declare function manifestToDependencies(manifestText: string): readonly Dependency[];
1024
1394
 
1395
+ /** Maximum byte size accepted for one scaffold artifact. */
1396
+ export declare const MAX_ARTIFACT_BYTES = 5242880;
1397
+
1398
+ /** Maximum hexadecimal string length representing one scaffold artifact. */
1399
+ export declare const MAX_ARTIFACT_HEX_LENGTH: number;
1400
+
1401
+ /** Maximum items accepted by one public package collection. */
1402
+ export declare const MAX_COLLECTION_ITEMS = 1000;
1403
+
1404
+ /** Maximum own keys inspected across one untrusted data-only graph boundary. */
1405
+ export declare const MAX_DATA_GRAPH_KEYS: number;
1406
+
1407
+ /** Maximum distinct records or arrays traversed at one untrusted data-only graph boundary. */
1408
+ export declare const MAX_DATA_GRAPH_NODES: number;
1409
+
1410
+ /** Maximum dependency package name length, including the canonical scope. */
1411
+ export declare const MAX_DEPENDENCY_NAME_LENGTH = 214;
1412
+
1413
+ /** Maximum UTF-8 bytes accepted for one package or host manifest. */
1414
+ export declare const MAX_MANIFEST_BYTES = 1048576;
1415
+
1416
+ /** Maximum bare workspace name length beneath the generated `@orkestrel/` scope. */
1417
+ export declare const MAX_NAME_LENGTH = 203;
1418
+
1419
+ /** Maximum general path length accepted at serialized package boundaries. */
1420
+ export declare const MAX_PATH_LENGTH = 32767;
1421
+
1422
+ /** Maximum package range or endpoint-sized token length. */
1423
+ export declare const MAX_RANGE_LENGTH = 2048;
1424
+
1425
+ /**
1426
+ * Maximum UTF-8 bytes accepted by a public serialized JSON parser.
1427
+ *
1428
+ * Four aggregate artifact budgets admit the hexadecimal and metadata overhead
1429
+ * of the largest supported contracts while bounding allocation before JSON parsing.
1430
+ */
1431
+ export declare const MAX_SERIALIZED_INPUT_BYTES: number;
1432
+
1433
+ /** Maximum aggregate bytes retained by one blueprint, plan, audit, or sync report. */
1434
+ export declare const MAX_TOTAL_ARTIFACT_BYTES = 104857600;
1435
+
1025
1436
  /** One declared public export of the scaffolded package; derived by `blueprintToMembers`, never authored. */
1026
1437
  export declare interface Member {
1027
1438
  readonly name: string;
1028
1439
  readonly category: Category;
1029
1440
  readonly summary: string;
1030
- readonly surface: Surface;
1441
+ readonly environment: Environment;
1031
1442
  }
1032
1443
 
1033
1444
  /**
@@ -1036,30 +1447,33 @@ export declare function coreViteConfig(): string;
1036
1447
  * @param name - The declared export name.
1037
1448
  * @param category - The `Member`'s `Category`.
1038
1449
  * @param summary - A one-line description.
1039
- * @param surface - The owning `Surface`; defaults `'core'`.
1450
+ * @param environment - The owning `Environment`; defaults `'core'`.
1040
1451
  * @returns A `Member` with every field set.
1041
1452
  *
1042
1453
  * @example
1043
1454
  * ```ts
1044
1455
  * import { member } from '@orkestrel/scaffold'
1045
1456
  *
1046
- * member('RouterOptions', 'type', 'Options for creating a Router.') // surface: 'core'
1457
+ * member('RouterOptions', 'type', 'Options for creating a Router.') // environment: 'core'
1047
1458
  * ```
1048
1459
  */
1049
- export declare function member(name: string, category: Category, summary: string, surface?: Surface): Member;
1460
+ export declare function member(name: string, category: Category, summary: string, environment?: Environment): Member;
1050
1461
 
1051
1462
  /**
1052
1463
  * Build the `Member` object shape.
1053
1464
  *
1054
- * @returns A fresh `ContractShape` describing `{ name, category, summary, surface }`.
1465
+ * @returns A fresh `ContractShape` describing `{ name, category, summary, environment }`.
1055
1466
  */
1056
1467
  export declare function memberShape(): ObjectShape<{
1057
1468
  name: StringShape;
1058
- category: LiteralShape<readonly ["type", "constant", "factory", "entity"]>;
1469
+ category: LiteralShape<readonly Category[]>;
1059
1470
  summary: StringShape;
1060
- surface: LiteralShape<readonly ["core", "browser", "server"]>;
1471
+ environment: LiteralShape<readonly Environment[]>;
1061
1472
  }, false>;
1062
1473
 
1474
+ /** The oldest Node version supported by the generated Vite toolchain. */
1475
+ export declare const MINIMUM_NODE_VERSION = "22.12.0";
1476
+
1063
1477
  /** The package-name RegExp — lowercase alphanumeric-with-hyphens, letter-first. */
1064
1478
  export declare const NAME_PATTERN: RegExp;
1065
1479
 
@@ -1072,7 +1486,10 @@ export declare function coreViteConfig(): string;
1072
1486
  export declare type Origin = 'host' | 'template' | 'computed';
1073
1487
 
1074
1488
  /** The three `Origin` values, frozen. */
1075
- export declare const ORIGINS: readonly ["host", "template", "computed"];
1489
+ export declare const ORIGINS: readonly Origin[];
1490
+
1491
+ /** The exact caret-pinned pre-1.0 range accepted for Orkestrel runtime dependencies. */
1492
+ export declare const ORKESTREL_RANGE_PATTERN: RegExp;
1076
1493
 
1077
1494
  /**
1078
1495
  * One caller template override.
@@ -1113,9 +1530,27 @@ export declare function coreViteConfig(): string;
1113
1530
  content: StringShape;
1114
1531
  }, false>;
1115
1532
 
1533
+ /**
1534
+ * Read one own data property without traversing a prototype or invoking an accessor.
1535
+ *
1536
+ * @param value - The candidate record.
1537
+ * @param key - The own property name to read.
1538
+ * @returns The data property's value, or `undefined` when it is absent, accessor-backed,
1539
+ * non-record, or cannot be inspected.
1540
+ *
1541
+ * @example
1542
+ * ```ts
1543
+ * import { ownDataValue } from '@orkestrel/scaffold'
1544
+ *
1545
+ * ownDataValue({ name: 'router' }, 'name') // 'router'
1546
+ * ownDataValue(Object.create({ name: 'inherited' }), 'name') // undefined
1547
+ * ```
1548
+ */
1549
+ export declare function ownDataValue(value: unknown, key: string): unknown;
1550
+
1116
1551
  /**
1117
1552
  * Compute the `package.json` artifact's `content`, applying the manifest and
1118
- * exports combination rules over a blueprint's surfaces — grounded against the
1553
+ * exports combination rules over a blueprint's src — grounded against the
1119
1554
  * live @orkestrel/middleware (core+server) and @orkestrel/router
1120
1555
  * (core+browser+server) exemplars.
1121
1556
  *
@@ -1152,12 +1587,12 @@ export declare function coreViteConfig(): string;
1152
1587
  /**
1153
1588
  * Build the computed `SELF_SPECIFIERS` / `SPECIFIER_MODULES` / `exportsFor`
1154
1589
  * block the `parityTest` template's `{{specifiers}}` placeholder fills —
1155
- * ONE shape for every surface count (grounded against the live single-surface
1156
- * websocket/indexeddb and multi-surface router/middleware exemplars, which
1590
+ * ONE shape for every environment count (grounded against the live single-environment
1591
+ * websocket/indexeddb and multi-environment router/middleware exemplars, which
1157
1592
  * both resolve a fence's specifier through a `SPECIFIER_MODULES` map rather
1158
1593
  * than a single-module lookup). The bare `@orkestrel/<name>` specifier
1159
- * resolves to the PRIMARY surface — `core` when declared, else the sole
1160
- * declared surface.
1594
+ * resolves to the PRIMARY environment — `core` when declared, else the sole
1595
+ * declared environment.
1161
1596
  *
1162
1597
  * @param spec - The `Blueprint` to derive the parity specifiers block from.
1163
1598
  * @returns The computed `parityTest` `{{specifiers}}` block content.
@@ -1181,7 +1616,34 @@ export declare function coreViteConfig(): string;
1181
1616
  * @param input - The value (or JSON string) to parse.
1182
1617
  * @returns A `Blueprint`, else `undefined`.
1183
1618
  */
1184
- export declare const parseBlueprint: (input: unknown) => Blueprint | undefined;
1619
+ export declare function parseBlueprint(input: unknown): Blueprint | undefined;
1620
+
1621
+ /**
1622
+ * Parse JSON only when its UTF-8 representation fits an explicit allocation budget.
1623
+ *
1624
+ * @param input - Serialized JSON text.
1625
+ * @param guard - Contract guard for the parsed value.
1626
+ * @param maximum - Maximum serialized UTF-8 bytes; defaults to the public input ceiling.
1627
+ * @returns The guarded value, or `undefined` when malformed, over budget, or off-contract.
1628
+ *
1629
+ * @example
1630
+ * ```ts
1631
+ * import { parseBoundedJSON } from '@orkestrel/scaffold'
1632
+ *
1633
+ * parseBoundedJSON('"ready"', (value): value is string => typeof value === 'string', 7)
1634
+ * // 'ready'
1635
+ * ```
1636
+ */
1637
+ export declare function parseBoundedJSON<T>(input: string, guard: Guard<T>, maximum?: number): T | undefined;
1638
+
1639
+ /**
1640
+ * Parse and own the exact `Compiler` constructor boundary before emitter allocation.
1641
+ *
1642
+ * @param input - Caller-supplied options.
1643
+ * @returns Fresh immutable options containing owned listener hooks.
1644
+ * @throws ScaffoldError with code INVALID for unknown keys, accessors, symbols, or hostile traps.
1645
+ */
1646
+ export declare function parseCompilerOptions(input: unknown): CompilerOptions;
1185
1647
 
1186
1648
  /**
1187
1649
  * Parse a `Plan` from `unknown` (or a JSON string), else `undefined`.
@@ -1195,7 +1657,34 @@ export declare function coreViteConfig(): string;
1195
1657
  * @param input - The value (or JSON string) to parse.
1196
1658
  * @returns A `Plan`, else `undefined`.
1197
1659
  */
1198
- export declare const parsePlan: (input: unknown) => Plan | undefined;
1660
+ export declare function parsePlan(input: unknown): Plan | undefined;
1661
+
1662
+ /**
1663
+ * Snapshot a bounded dense array of unique plan ids without invoking its iterator.
1664
+ *
1665
+ * @param input - The untrusted batch-removal boundary.
1666
+ * @returns A frozen id array, or `undefined` for accessors, symbols, holes,
1667
+ * duplicates, non-string values, excessive length, or hostile proxy traps.
1668
+ *
1669
+ * @example
1670
+ * ```ts
1671
+ * import { parsePlanIds } from '@orkestrel/scaffold'
1672
+ *
1673
+ * parsePlanIds(['a', 'b']) // ['a', 'b']
1674
+ * parsePlanIds(['a', 'a']) // undefined
1675
+ * ```
1676
+ */
1677
+ export declare function parsePlanIds(input: unknown): readonly string[] | undefined;
1678
+
1679
+ /**
1680
+ * Parse and own the exact `PlanManager` constructor boundary before resource allocation.
1681
+ *
1682
+ * @param input - Caller-supplied options.
1683
+ * @returns Fresh options containing immutable plan snapshots and own listener hooks.
1684
+ * @throws ScaffoldError with code INVALID for unknown keys, accessors, symbols,
1685
+ * hostile traps, malformed hooks, or malformed/unbounded seed plans.
1686
+ */
1687
+ export declare function parsePlanManagerOptions(input: unknown): PlanManagerOptions;
1199
1688
 
1200
1689
  /**
1201
1690
  * Parse a `SyncReport` from `unknown` (or a JSON string), else `undefined`.
@@ -1209,7 +1698,7 @@ export declare function coreViteConfig(): string;
1209
1698
  * @param input - The value (or JSON string) to parse.
1210
1699
  * @returns A `SyncReport`, else `undefined`.
1211
1700
  */
1212
- export declare const parseSyncReport: (input: unknown) => SyncReport | undefined;
1701
+ export declare function parseSyncReport(input: unknown): SyncReport | undefined;
1213
1702
 
1214
1703
  /**
1215
1704
  * Derive the PascalCase entity name from a lowercase-hyphen package name.
@@ -1234,19 +1723,26 @@ export declare function coreViteConfig(): string;
1234
1723
  * `hash` is a canonical `computeHash` digest of the plan's
1235
1724
  * blueprint/groups/artifacts, serialized through `stableStringify` —
1236
1725
  * deterministic, no clocks or randomness. `trace` is a one-line derivation
1237
- * summary built from the plan's own `PlanSummary`.
1726
+ * summary built from the plan's own `PlanSummary`; its explicit `src:` and
1727
+ * `app:` fields use `none` when that independent axis is empty.
1238
1728
  * @returns The plan with `trace` and `hash` filled.
1239
1729
  *
1240
1730
  * @example
1241
1731
  * ```ts
1242
1732
  * import { pinPlan } from '@orkestrel/scaffold'
1243
1733
  *
1244
- * pinPlan(plan).trace // 'router · core+browser · groups:7 · artifacts:21'
1734
+ * pinPlan(plan).trace // 'router · src:core+browser · app:none · groups:7 · artifacts:21'
1245
1735
  * ```
1246
1736
  */
1247
1737
  export declare function pinPlan(plan: Plan): Plan;
1248
1738
 
1249
- /** The compiled, ordered artifact list plus the selection it covers; `trace` / `hash` filled by the pin. */
1739
+ /**
1740
+ * The compiled, ordered artifact list plus the independent source/application selection it covers.
1741
+ *
1742
+ * @remarks
1743
+ * `pinPlan` fills `trace` with explicit `src:` and `app:` axes and fills
1744
+ * `hash` from the plan's identity payload.
1745
+ */
1250
1746
  export declare interface Plan {
1251
1747
  readonly blueprint: Blueprint;
1252
1748
  readonly groups: readonly Group[];
@@ -1263,17 +1759,20 @@ export declare function coreViteConfig(): string;
1263
1759
  * `hash` — deterministic, no randomness. Re-adding a plan whose content is
1264
1760
  * unchanged resolves to the SAME id and returns the existing record
1265
1761
  * untouched (`version` stays put); a plan whose content differs mints a
1266
- * fresh id at `version: 1`. The array overload of `remove` is declared FIRST
1267
- * (AGENTS §9.2) so an id list resolves to the batch form; the batch form is
1268
- * ALL-OR-NOTHING. After `destroy()` every method but the getters and
1269
- * `destroy` itself throws `ScaffoldError('DESTROYED', …)`.
1762
+ * fresh id at `version: 1`, while a distinct canonical payload with the same
1763
+ * digest throws `INVALID`. Every stored plan and returned record is a detached,
1764
+ * recursively frozen snapshot. The array overload of `remove` is declared
1765
+ * FIRST (AGENTS §9.2) so an id list resolves to the batch form; the batch form
1766
+ * is ALL-OR-NOTHING and commits every deletion before emitting. After
1767
+ * `destroy()` every method but the getters and `destroy` itself throws
1768
+ * `ScaffoldError('DESTROYED', …)`.
1270
1769
  *
1271
1770
  * @example
1272
1771
  * ```ts
1273
1772
  * import { blueprint, blueprintToPlan, PlanManager } from '@src/core'
1274
1773
  *
1275
1774
  * const plans = new PlanManager()
1276
- * const record = plans.add(blueprintToPlan(blueprint('budget', { surfaces: ['core'] })))
1775
+ * const record = plans.add(blueprintToPlan(blueprint('budget', { src: ['core'] })))
1277
1776
  * record.id === record.hash // true — id minted from content
1278
1777
  * plans.destroy()
1279
1778
  * ```
@@ -1312,7 +1811,7 @@ export declare function coreViteConfig(): string;
1312
1811
  *
1313
1812
  * @example
1314
1813
  * ```ts
1315
- * const record = plans.add(blueprintToPlan(blueprint('budget', { surfaces: ['core'] })))
1814
+ * const record = plans.add(blueprintToPlan(blueprint('budget', { src: ['core'] })))
1316
1815
  * record.version // 1
1317
1816
  * ```
1318
1817
  */
@@ -1327,7 +1826,8 @@ export declare function coreViteConfig(): string;
1327
1826
  * `remove(id)` removes one plan, emitting `remove` and returning `true`
1328
1827
  * when it existed, `false` otherwise. `remove(ids)` is ALL-OR-NOTHING: if
1329
1828
  * any listed id is unregistered, the collection is left untouched and
1330
- * `false` is returned.
1829
+ * `false` is returned. Successful batch and remove-all calls commit every
1830
+ * deletion before the first stable-order event.
1331
1831
  *
1332
1832
  * @param target - Omit to remove all, a single id, or a list of ids.
1333
1833
  * @returns `boolean` for the single-id / list-of-ids forms; `void` for the remove-all form.
@@ -1339,7 +1839,7 @@ export declare function coreViteConfig(): string;
1339
1839
  destroy(): void;
1340
1840
  }
1341
1841
 
1342
- /** `PlanManager`'s push observation surface (AGENTS §13). */
1842
+ /** `PlanManager`'s push observation channel (AGENTS §13). */
1343
1843
  export declare type PlanManagerEventMap = {
1344
1844
  readonly add: readonly [id: string];
1345
1845
  readonly remove: readonly [id: string];
@@ -1367,6 +1867,21 @@ export declare function coreViteConfig(): string;
1367
1867
  readonly error?: EmitterErrorHandler;
1368
1868
  }
1369
1869
 
1870
+ /**
1871
+ * Serialize exactly the content that establishes a plan's identity.
1872
+ *
1873
+ * @param plan - The plan whose identity payload to serialize.
1874
+ * @returns The canonical blueprint, group, and artifact payload.
1875
+ *
1876
+ * @example
1877
+ * ```ts
1878
+ * import { planPayload } from '@orkestrel/scaffold'
1879
+ *
1880
+ * planPayload(plan) === planPayload({ ...plan, trace: 'different' }) // true
1881
+ * ```
1882
+ */
1883
+ export declare function planPayload(plan: Plan): string;
1884
+
1370
1885
  /** A versioned, content-hashed `Plan` inside a `PlanManager`. */
1371
1886
  export declare interface PlanRecord {
1372
1887
  readonly id: string;
@@ -1389,7 +1904,8 @@ export declare function coreViteConfig(): string;
1389
1904
  name: StringShape;
1390
1905
  description: OptionalShape<StringShape>;
1391
1906
  keywords: ArrayShape<StringShape>;
1392
- surfaces: ArrayShape<LiteralShape<readonly ["core", "browser", "server"]>>;
1907
+ src: ArrayShape<LiteralShape<readonly Environment[]>>;
1908
+ app: ArrayShape<LiteralShape<readonly Environment[]>>;
1393
1909
  dependencies: ArrayShape<ObjectShape<{
1394
1910
  name: StringShape;
1395
1911
  range: StringShape;
@@ -1411,24 +1927,32 @@ export declare function coreViteConfig(): string;
1411
1927
  path: StringShape;
1412
1928
  content: StringShape;
1413
1929
  }, false>>;
1930
+ engine: BooleanShape;
1414
1931
  }, false>;
1415
- groups: ArrayShape<LiteralShape<readonly ["manifest", "configs", "source", "tests", "guides", "docs", "orchestration"]>>;
1416
- artifacts: ArrayShape<ObjectShape<{
1932
+ groups: ArrayShape<LiteralShape<readonly Group[]>>;
1933
+ artifacts: ArrayShape<UnionShape<[ ObjectShape<{
1417
1934
  path: StringShape;
1418
- group: LiteralShape<readonly ["manifest", "configs", "source", "tests", "guides", "docs", "orchestration"]>;
1419
- origin: LiteralShape<readonly ["host", "template", "computed"]>;
1420
- surface: OptionalShape<LiteralShape<readonly ["core", "browser", "server"]>>;
1421
- content: OptionalShape<StringShape>;
1935
+ group: LiteralShape<readonly Group[]>;
1936
+ origin: LiteralShape<readonly ["host"]>;
1937
+ environment: OptionalShape<LiteralShape<readonly Environment[]>>;
1938
+ hex: OptionalShape<StringShape>;
1422
1939
  source: OptionalShape<StringShape>;
1423
- }, false>>;
1940
+ }, false>, ObjectShape<{
1941
+ path: StringShape;
1942
+ group: LiteralShape<readonly Group[]>;
1943
+ origin: LiteralShape<readonly ["template", "computed"]>;
1944
+ environment: OptionalShape<LiteralShape<readonly Environment[]>>;
1945
+ content: StringShape;
1946
+ }, false>]>>;
1424
1947
  trace: OptionalShape<StringShape>;
1425
1948
  hash: OptionalShape<StringShape>;
1426
1949
  }, false>;
1427
1950
 
1428
- /** The dry-run tally. */
1951
+ /** The dry-run tally, including the independent source and application environment selections. */
1429
1952
  export declare interface PlanSummary {
1430
1953
  readonly name: string;
1431
- readonly surfaces: readonly Surface[];
1954
+ readonly src: readonly Environment[];
1955
+ readonly app: readonly Environment[];
1432
1956
  readonly groups: readonly Group[];
1433
1957
  readonly artifacts: number;
1434
1958
  readonly host: number;
@@ -1455,7 +1979,7 @@ export declare function coreViteConfig(): string;
1455
1979
  * Project a `Plan` into a `PlanSummary`.
1456
1980
  *
1457
1981
  * @param plan - The plan to summarize.
1458
- * @returns The artifact tally by `origin`, the surfaces, and the covered groups.
1982
+ * @returns The artifact tally by `origin`, both environment axes, and the covered groups.
1459
1983
  *
1460
1984
  * @example
1461
1985
  * ```ts
@@ -1466,6 +1990,9 @@ export declare function coreViteConfig(): string;
1466
1990
  */
1467
1991
  export declare function planToSummary(plan: Plan): PlanSummary;
1468
1992
 
1993
+ /** Build the dedicated Node-only repository policy Vitest project. */
1994
+ export declare function policyViteProject(): string;
1995
+
1469
1996
  /**
1470
1997
  * One validation issue.
1471
1998
  *
@@ -1502,10 +2029,67 @@ export declare function coreViteConfig(): string;
1502
2029
  export declare function rangeToFreshness(range: string, latest: string): Freshness;
1503
2030
 
1504
2031
  /**
1505
- * The root `tsconfig.json` one `@src/<surface>` path alias per declared
1506
- * surface, in declared order.
2032
+ * Render a JSON array through `formatJson`'s inline-or-broken rule inline
2033
+ * when the rendered width (via `computeColumnWidth`) fits `JSON_PRINT_WIDTH`, one
2034
+ * item per line otherwise.
2035
+ *
2036
+ * @param entries - The array's elements, in order.
2037
+ * @param indent - The current indentation prefix.
2038
+ * @param prefix - The text already emitted on this line before the array.
2039
+ * @param suffix - The text that will follow the array on this line.
2040
+ * @returns The rendered array fragment (no trailing newline).
2041
+ *
2042
+ * @example
2043
+ * ```ts
2044
+ * import { renderArray } from '@orkestrel/scaffold'
2045
+ *
2046
+ * renderArray(['ESNext', 'DOM'], '', '', '') // '["ESNext", "DOM"]'
2047
+ * ```
2048
+ */
2049
+ export declare function renderArray(entries: readonly unknown[], indent: string, prefix: string, suffix: string): string;
2050
+
2051
+ /**
2052
+ * Render a JSON object through `formatJson`'s one-key-per-line rule.
2053
+ *
2054
+ * @param entry - The object to render.
2055
+ * @param indent - The current indentation prefix.
2056
+ * @returns The rendered object fragment (no trailing newline).
2057
+ *
2058
+ * @example
2059
+ * ```ts
2060
+ * import { renderObject } from '@orkestrel/scaffold'
2061
+ *
2062
+ * renderObject({ lib: ['ESNext'] }, '') // '{\n\t"lib": ["ESNext"]\n}'
2063
+ * ```
2064
+ */
2065
+ export declare function renderObject(entry: Readonly<Record<string, unknown>>, indent: string): string;
2066
+
2067
+ /**
2068
+ * Render one JSON value through `formatJson`'s dispatch — arrays via
2069
+ * `renderArray`, objects via `renderObject`, everything else via
2070
+ * `JSON.stringify`.
2071
+ *
2072
+ * @param entry - The value to render.
2073
+ * @param indent - The current indentation prefix.
2074
+ * @param prefix - The text already emitted on this line before `entry`.
2075
+ * @param suffix - The text that will follow `entry` on this line.
2076
+ * @returns The rendered fragment (no trailing newline).
2077
+ *
2078
+ * @example
2079
+ * ```ts
2080
+ * import { renderValue } from '@orkestrel/scaffold'
2081
+ *
2082
+ * renderValue('ESNext', '', '', '') // '"ESNext"'
2083
+ * ```
2084
+ */
2085
+ export declare function renderValue(entry: unknown, indent: string, prefix: string, suffix: string): string;
2086
+
2087
+ /**
2088
+ * The root `tsconfig.json` — one `@src/<environment>` path alias per declared
2089
+ * environment, in declared order.
1507
2090
  *
1508
- * @param surfaces - The declared `Surface[]`.
2091
+ * @param src - The declared `Environment[]`.
2092
+ * @param app - The declared application environments, defaulting to none.
1509
2093
  * @returns The root `tsconfig.json` file content, newline-terminated.
1510
2094
  *
1511
2095
  * @example
@@ -1513,26 +2097,30 @@ export declare function coreViteConfig(): string;
1513
2097
  * rootTsconfig(['core']) // '{\n\t"compilerOptions": {…}\n}\n'
1514
2098
  * ```
1515
2099
  */
1516
- export declare function rootTsconfig(surfaces: readonly Surface[]): string;
2100
+ export declare function rootTsconfig(src: readonly Environment[], app?: readonly Environment[]): string;
1517
2101
 
1518
2102
  /**
1519
2103
  * The root `vite.config.ts` — three grounded shapes, chosen by a blueprint's
1520
- * `surfaces`:
2104
+ * `src`:
1521
2105
  * 1. `core`-only — `srcCore` + `guides`, no Playwright at all (the live
1522
2106
  * timeout exemplar: no browser project exists anywhere in the file).
1523
- * 2. Multi-surface (2+ surfaces, always including `core` per the live
2107
+ * 2. Multi-environment (2+ src, always including `core` per the live
1524
2108
  * middleware/router exemplars) — `srcCore` is the shared base;
1525
2109
  * `srcBrowser` / `srcServer` extend it and externalize `@src/core` to
1526
2110
  * the sibling build. Playwright ships UNCONDITIONALLY (middleware
1527
- * carries it with no browser surface — grounded, not conditional).
1528
- * 3. A single non-`core` surface (`browser`-only / `server`-only) — the
1529
- * surface factory itself IS the base (no `srcCore` to extend, so no
2111
+ * carries it with no browser environment — grounded, not conditional).
2112
+ * 3. A single non-`core` environment (`browser`-only / `server`-only) — the
2113
+ * environment factory itself IS the base (no `srcCore` to extend, so no
1530
2114
  * dead `@src/core` externalize/remap either — there is no sibling
1531
2115
  * core build), per the live sqlite (server-only) / indexeddb
1532
2116
  * (browser-only) exemplars. Playwright ships only when the sole
1533
- * surface is `browser` (it must run its own tests in a real browser).
2117
+ * environment is `browser` (it must run its own tests in a real browser).
1534
2118
  *
1535
- * @param surfaces - The declared `Surface[]`.
2119
+ * @param src - The declared `Environment[]`.
2120
+ * @param engine - Structural: `true` appends the `srcBin` project (an
2121
+ * executable build target, never a barrel) after the other declared
2122
+ * projects — the self-hosting tax, grounded against this very repo's own
2123
+ * checked-in `vite.config.ts`.
1536
2124
  * @returns The root `vite.config.ts` file content, newline-terminated.
1537
2125
  *
1538
2126
  * @example
@@ -1540,10 +2128,10 @@ export declare function coreViteConfig(): string;
1540
2128
  * rootViteConfig(['core']).includes('srcCore') // true
1541
2129
  * ```
1542
2130
  */
1543
- export declare function rootViteConfig(surfaces: readonly Surface[]): string;
2131
+ export declare function rootViteConfig(src: readonly Environment[], engine?: boolean): string;
1544
2132
 
1545
2133
  /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
1546
- export declare const SCAFFOLD_RANGE = "^0.0.1";
2134
+ export declare const SCAFFOLD_RANGE = "^0.0.2";
1547
2135
 
1548
2136
  /**
1549
2137
  * Carries a `ScaffoldErrorCode` + optional `context` (AGENTS §12).
@@ -1551,7 +2139,7 @@ export declare function coreViteConfig(): string;
1551
2139
  * @remarks
1552
2140
  * Throws are reserved for caller misuse: `createBlueprint` on off-contract
1553
2141
  * data throws `INVALID`, any method after `destroy()` throws `DESTROYED`, and
1554
- * on the server surface a non-vacant target throws `TARGET` while a failed
2142
+ * in the server environment a non-vacant target throws `TARGET` while a failed
1555
2143
  * write throws `WRITE`. A failing gate is NOT an error — it fails closed into
1556
2144
  * an incomplete `Scaffolding` whose `failures` carry a `BLOCKED` marker.
1557
2145
  *
@@ -1587,28 +2175,78 @@ export declare function coreViteConfig(): string;
1587
2175
  }
1588
2176
 
1589
2177
  /**
1590
- * The single non-`core` surface's factory IS the base (Shape 3 of
1591
- * `rootViteConfig`) — the surface's own `viteHeader` (Playwright only when
1592
- * `surface === 'browser'`, per the live sqlite/indexeddb exemplars) prefixes
1593
- * the surface-specific `srcBrowser` / `srcServer` + `guides` projects export.
2178
+ * Serialize text as a single-quoted TypeScript string literal.
2179
+ *
2180
+ * @param value - The untrusted text value.
2181
+ * @returns A source literal preserving every UTF-16 code unit.
2182
+ *
2183
+ * @example
2184
+ * ```ts
2185
+ * import { serializeTypeScriptString } from '@orkestrel/scaffold'
2186
+ *
2187
+ * serializeTypeScriptString("app's") // "'app\\'s'"
2188
+ * ```
2189
+ */
2190
+ export declare function serializeTypeScriptString(value: string): string;
2191
+
2192
+ /** Immutable official actions/setup-node v6.4.0 commit used by generated CI. */
2193
+ export declare const SETUP_NODE_ACTION_SHA = "48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e";
2194
+
2195
+ /**
2196
+ * The single non-`core` environment's factory IS the base (Shape 3 of
2197
+ * `rootViteConfig`) — the environment's own `viteHeader` (Playwright only when
2198
+ * `environment === 'browser'`, per the live sqlite/indexeddb exemplars) prefixes
2199
+ * the environment-specific `srcBrowser` / `srcServer` + `guides` projects export.
1594
2200
  *
1595
- * @param surface - The sole declared non-`core` surface.
1596
- * @returns The root `vite.config.ts` file content for a single non-`core` surface, newline-terminated.
2201
+ * @param environment - The sole declared non-`core` environment.
2202
+ * @returns The root `vite.config.ts` file content for a single non-`core` environment, newline-terminated.
1597
2203
  *
1598
2204
  * @example
1599
2205
  * ```ts
1600
- * singleSurfaceViteConfig('server').includes('srcServer') // true
2206
+ * singleSrcViteConfig('server').includes('srcServer') // true
1601
2207
  * ```
1602
2208
  */
1603
- export declare function singleSurfaceViteConfig(surface: 'browser' | 'server'): string;
2209
+ export declare function singleSrcViteConfig(environment: 'browser' | 'server'): string;
2210
+
2211
+ /** Exact lowercase hexadecimal target bytes keyed by artifact-relative path. */
2212
+ export declare type Snapshot = Readonly<Record<string, string>>;
2213
+
2214
+ /**
2215
+ * Build an exact-byte snapshot from text content keyed by artifact path.
2216
+ *
2217
+ * @param current - Text content keyed by artifact path.
2218
+ * @returns The same keys with UTF-8 bytes encoded as lowercase hexadecimal.
2219
+ */
2220
+ export declare function snapshotOf(current: Readonly<Record<string, string>>): Snapshot;
2221
+
2222
+ /**
2223
+ * Clone and recursively freeze a plan into an immutable owned snapshot.
2224
+ *
2225
+ * @param input - The untrusted plan boundary to snapshot.
2226
+ * @returns A detached, recursively frozen plan.
2227
+ * @throws ScaffoldError with code INVALID when the input is off-contract,
2228
+ * accessor-backed, uncloneable, or cannot be frozen.
2229
+ *
2230
+ * @example
2231
+ * ```ts
2232
+ * import { snapshotPlan } from '@orkestrel/scaffold'
2233
+ *
2234
+ * const snapshot = snapshotPlan(plan)
2235
+ * Object.isFrozen(snapshot.blueprint) // true
2236
+ * ```
2237
+ */
2238
+ export declare function snapshotPlan(input: unknown): Plan;
2239
+
2240
+ /** Additional development dependency required by a published browser source environment. */
2241
+ export declare const SOURCE_BROWSER_DEV_DEPENDENCIES: Readonly<Record<string, string>>;
1604
2242
 
1605
2243
  /**
1606
2244
  * Draft the `source` group's `template` artifacts — the generated-minimal
1607
- * `src/<surface>/*` stubs, one full {types, <Pascal>, factories, index} set
1608
- * PER declared surface (never assuming `core`), filled from `TEMPLATES` with
2245
+ * `src/<environment>/*` stubs, one full {types, <Pascal>, factories, index} set
2246
+ * PER declared environment (never assuming `core`), filled from `TEMPLATES` with
1609
2247
  * `missing: 'error'`. `blueprintToMembers` already declares a full entity +
1610
- * factory per surface (AGENTS §5's per-surface centralized-file pattern), so
1611
- * every surface gets the same uniform stub shape.
2248
+ * factory per environment (AGENTS §5's per-environment centralized-file pattern), so
2249
+ * every environment gets the same uniform stub shape.
1612
2250
  *
1613
2251
  * @param spec - The `Blueprint` to derive source stubs from.
1614
2252
  * @param pascal - The package's PascalCase entity name.
@@ -1641,100 +2279,86 @@ export declare function coreViteConfig(): string;
1641
2279
  export declare function splitTableRow(line: string): readonly string[];
1642
2280
 
1643
2281
  /**
1644
- * Serialize a value to a canonical, key-order-INDEPENDENT JSON-like string.
1645
- *
1646
- * @param value - The value to stringify.
1647
- * @remarks
1648
- * Object keys sort code-unit; array order is preserved. So two
1649
- * logically-equal blueprints built with their fields in a different
1650
- * construction order still hash identically once fed through `computeHash`.
1651
- * @returns The canonical string form of `value`.
1652
- *
1653
- * @example
1654
- * ```ts
1655
- * import { stableStringify } from '@orkestrel/scaffold'
1656
- *
1657
- * stableStringify({ b: 1, a: 2 }) // '{"a":2,"b":1}'
1658
- * ```
1659
- */
1660
- export declare function stableStringify(value: unknown): string;
1661
-
1662
- /** The environment surface an artifact or member belongs to (the SCAFFOLDED package's faces, not scaffold's own). */
1663
- export declare type Surface = 'core' | 'browser' | 'server';
1664
-
1665
- /**
1666
- * The per-surface variant matrix as data: per `Surface`, its `configs/src`
2282
+ * The per-environment variant matrix as data: per `Environment`, its `configs/src`
1667
2283
  * files, Vitest project label, `exports` subpath, and build formats — the
1668
- * per-surface layer `blueprintToPlan` reads BENEATH the manifest/exports
2284
+ * per-environment layer `blueprintToPlan` reads BENEATH the manifest/exports
1669
2285
  * combination rules it applies on top.
1670
2286
  */
1671
- export declare const SURFACE_MATRIX: Readonly<{
1672
- readonly core: Readonly<{
1673
- configs: readonly ["configs/src/vite.core.config.ts", "configs/src/tsconfig.core.json"];
1674
- project: "src:core";
1675
- path: ".";
1676
- formats: readonly ["es", "cjs"];
1677
- }>;
1678
- readonly browser: Readonly<{
1679
- configs: readonly ["configs/src/vite.browser.config.ts", "configs/src/tsconfig.browser.json"];
1680
- project: "src:browser";
1681
- path: "./browser";
1682
- formats: readonly ["es"];
1683
- }>;
1684
- readonly server: Readonly<{
1685
- configs: readonly ["configs/src/vite.server.config.ts", "configs/src/tsconfig.server.json"];
1686
- project: "src:server";
1687
- path: "./server";
1688
- formats: readonly ["es", "cjs"];
1689
- }>;
1690
- }>;
1691
-
1692
- /** The three `Surface` values, frozen — compose with `literalOf(...)` / `parseEnum(...)`. */
1693
- export declare const SURFACES: readonly ["core", "browser", "server"];
2287
+ export declare const SRC_MATRIX: Readonly<Record<Environment, SrcDefinition>>;
2288
+
2289
+ /** The deterministic build and export settings for one source environment. */
2290
+ export declare interface SrcDefinition {
2291
+ readonly configs: readonly string[];
2292
+ readonly project: string;
2293
+ readonly path: string;
2294
+ readonly formats: readonly BuildFormat[];
2295
+ }
1694
2296
 
1695
2297
  /**
1696
2298
  * `configs/src/tsconfig.<browser|server>.json` — `rootDir`/`outDir` point at
1697
- * the whole `src`/`dist/src` tree (not a per-surface subfolder), per the live
2299
+ * the whole `src`/`dist/src` tree (not a per-environment subfolder), per the live
1698
2300
  * middleware/router exemplars.
1699
2301
  *
1700
- * @param surface - The non-`core` surface to derive the `tsconfig` for.
1701
- * @returns The surface `tsconfig` file content, newline-terminated.
2302
+ * @param environment - The non-`core` environment to derive the `tsconfig` for.
2303
+ * @returns The environment `tsconfig` file content, newline-terminated.
1702
2304
  *
1703
2305
  * @example
1704
2306
  * ```ts
1705
- * surfaceTsconfig('server').includes('"rootDir": "../../src"') // true
2307
+ * srcTsconfig('server').includes('"rootDir": "../../src"') // true
1706
2308
  * ```
1707
2309
  */
1708
- export declare function surfaceTsconfig(surface: 'browser' | 'server'): string;
2310
+ export declare function srcTsconfig(environment: 'browser' | 'server'): string;
1709
2311
 
1710
2312
  /**
1711
- * Classify a blueprint's surfaces into the manifest/exports variant class.
2313
+ * Classify a blueprint's src into the manifest/exports variant class.
1712
2314
  *
1713
- * @param surfaces - The declared `Surface[]`.
1714
- * @returns The sole declared `Surface`, or `'multi'` when two or more are declared.
2315
+ * @param src - The declared `Environment[]`.
2316
+ * @returns The sole declared `Environment`, or `'multi'` when two or more are declared.
1715
2317
  *
1716
2318
  * @example
1717
2319
  * ```ts
1718
- * surfaceVariant(['core']) // 'core'
1719
- * surfaceVariant(['core', 'server']) // 'multi'
2320
+ * srcVariant(['core']) // 'core'
2321
+ * srcVariant(['core', 'server']) // 'multi'
1720
2322
  * ```
1721
2323
  */
1722
- export declare function surfaceVariant(surfaces: readonly Surface[]): Surface | 'multi';
2324
+ export declare function srcVariant(src: readonly Environment[]): Environment | 'multi';
1723
2325
 
1724
2326
  /**
1725
2327
  * `configs/src/vite.<browser|server>.config.ts` — a thin `dts`-only wrapper;
1726
2328
  * `build.lib` / externals live in the root `srcBrowser` / `srcServer` export
1727
2329
  * instead (per the live exemplars).
1728
2330
  *
1729
- * @param surface - The non-`core` surface to derive the `vite.config.ts` for.
1730
- * @returns The surface `vite.config.ts` file content, newline-terminated.
2331
+ * @param environment - The non-`core` environment to derive the `vite.config.ts` for.
2332
+ * @returns The environment `vite.config.ts` file content, newline-terminated.
1731
2333
  *
1732
2334
  * @example
1733
2335
  * ```ts
1734
- * surfaceViteConfig('browser').includes('srcBrowser') // true
2336
+ * srcViteConfig('browser').includes('srcBrowser') // true
1735
2337
  * ```
1736
2338
  */
1737
- export declare function surfaceViteConfig(surface: 'browser' | 'server'): string;
2339
+ export declare function srcViteConfig(environment: 'browser' | 'server'): string;
2340
+
2341
+ /**
2342
+ * Serialize a value to a canonical, key-order-INDEPENDENT JSON-like string.
2343
+ *
2344
+ * @param value - The value to stringify.
2345
+ * @remarks
2346
+ * Object keys sort code-unit; array order is preserved. So two
2347
+ * logically-equal blueprints built with their fields in a different
2348
+ * construction order still hash identically once fed through `computeHash`.
2349
+ * @returns The canonical string form of `value`.
2350
+ *
2351
+ * @example
2352
+ * ```ts
2353
+ * import { stableStringify } from '@orkestrel/scaffold'
2354
+ *
2355
+ * stableStringify({ b: 1, a: 2 }) // '{"a":2,"b":1}'
2356
+ * ```
2357
+ */
2358
+ export declare function stableStringify(value: unknown): string;
2359
+
2360
+ /** Target-aware guide baseline: an absence marker or exact SHA-256 digest. */
2361
+ export declare const SYNC_BASELINE_PATTERN: RegExp;
1738
2362
 
1739
2363
  /**
1740
2364
  * The whole outcome of a `Sync.pull`.
@@ -1767,14 +2391,15 @@ export declare function coreViteConfig(): string;
1767
2391
  name: StringShape;
1768
2392
  path: StringShape;
1769
2393
  content: StringShape;
1770
- freshness: LiteralShape<readonly ["current", "behind", "missing", "failed"]>;
2394
+ freshness: LiteralShape<readonly Freshness[]>;
1771
2395
  note: OptionalShape<StringShape>;
2396
+ baseline: OptionalShape<StringShape>;
1772
2397
  }, boolean | ContractShape>>;
1773
2398
  versions: ArrayShape<ObjectShape<{
1774
2399
  name: StringShape;
1775
2400
  range: StringShape;
1776
2401
  latest: StringShape;
1777
- freshness: LiteralShape<readonly ["current", "behind", "missing", "failed"]>;
2402
+ freshness: LiteralShape<readonly Freshness[]>;
1778
2403
  note: OptionalShape<StringShape>;
1779
2404
  }, boolean | ContractShape>>;
1780
2405
  clean: BooleanShape;
@@ -1801,7 +2426,7 @@ export declare function coreViteConfig(): string;
1801
2426
  * `template`-origin artifact `blueprintToPlan` renders.
1802
2427
  *
1803
2428
  * @remarks
1804
- * The generated-minimal stub prose/source, expressed as `{{name}}` /
2429
+ * The generated-minimal starter prose/source, expressed as `{{name}}` /
1805
2430
  * `{{pascal}}` `{{token}}` placeholders for `@orkestrel/template`'s pure
1806
2431
  * `fillTemplate` LEAF. Only genuinely templated PROSE / source artifacts live
1807
2432
  * here — the token-collision boundary (AGENTS §14, this guide's Contract
@@ -1815,10 +2440,10 @@ export declare function coreViteConfig(): string;
1815
2440
 
1816
2441
  /**
1817
2442
  * Draft the `tests` group's `template` artifacts — the shared recorder
1818
- * setup, one environment-specific setup file per non-`core` surface
2443
+ * setup, one environment-specific setup file per non-`core` environment
1819
2444
  * (`setupServer.ts` / `setupBrowser.ts`, grounded against the live
1820
2445
  * exemplars' setup-file naming), the generated-minimal entity / factory test
1821
- * stubs PER declared surface, and the surface-aware guides-parity drop-in.
2446
+ * stubs PER declared environment, and the environment-aware guides-parity drop-in.
1822
2447
  *
1823
2448
  * @param spec - The `Blueprint` to derive test stubs from.
1824
2449
  * @param pascal - The package's PascalCase entity name.
@@ -1831,21 +2456,23 @@ export declare function coreViteConfig(): string;
1831
2456
  */
1832
2457
  export declare function testArtifacts(spec: Blueprint, pascal: string): readonly Artifact[];
1833
2458
 
2459
+ /** TypeScript module extensions every generated scoped configuration checks. */
2460
+ export declare const TYPESCRIPT_EXTENSIONS: readonly string[];
2461
+
1834
2462
  /**
1835
2463
  * The semantic pass over a blueprint.
1836
2464
  *
1837
2465
  * @param spec - The blueprint to validate.
1838
2466
  * @remarks
1839
- * Checks the name against `NAME_PATTERN`, non-empty on-vocabulary `surfaces`
1840
- * with no repeats (a repeat would produce duplicate members); a single
1841
- * surface `core`-only, `server`-only, `browser`-only is a fully
1842
- * first-class declaration (`rootViteConfig` retargets the root export and
1843
- * runs the surface's own factory as the base, no `core` involved), but a
1844
- * `browser`+`server` declaration with no `core` has no defined configuration
1845
- * class `rootViteConfig` / `singleSurfaceViteConfig` can shape that ONE
1846
- * exemplar-less combination is a blocking question (without this gate it
1847
- * would silently drop a surface at `rootViteConfig`'s dispatch while the
1848
- * manifest still references it). And well-formed `dependencies` / `peers` /
2467
+ * Checks the name against `NAME_PATTERN` and `MAX_NAME_LENGTH`, requires at
2468
+ * least one selected environment across the published `src` and private `app`
2469
+ * axes, and keeps both axes on-vocabulary with no repeats (a repeat would
2470
+ * produce duplicate members). A single environment `core`-only, `server`-only, or
2471
+ * `browser`-only is first-class on either axis, but a `browser`+`server`
2472
+ * declaration with no `core` in the same axis has no defined shared
2473
+ * configuration class. That ONE exemplar-less combination is a blocking
2474
+ * question; without the gate dispatch would silently drop an environment. Also checks
2475
+ * well-formed `dependencies` / `peers` /
1849
2476
  * `extras` (non-empty name/range, no duplicate names within an array):
1850
2477
  * `dependencies` and `peers` names are shaped `DEPENDENCY_NAME_PATTERN`
1851
2478
  * (closed to `@orkestrel/*`) — a NAME-shaped law at the gate that closes the
@@ -1897,6 +2524,25 @@ export declare function coreViteConfig(): string;
1897
2524
  readonly seen: ReadonlySet<string>;
1898
2525
  };
1899
2526
 
2527
+ /**
2528
+ * Validate both a plan's blueprint semantics and every override against the
2529
+ * exact artifact set the plan would materialize.
2530
+ *
2531
+ * @param plan - The structurally valid plan to validate before mutation.
2532
+ * @returns A total validation whose blocking questions include missing,
2533
+ * host-owned, and publication-boundary override targets.
2534
+ *
2535
+ * @example
2536
+ * ```ts
2537
+ * import { blueprint, blueprintToPlan, validatePlan } from '@orkestrel/scaffold'
2538
+ *
2539
+ * const plan = blueprintToPlan(blueprint('router', { src: ['core'] }))
2540
+ *
2541
+ * validatePlan(plan).valid // true
2542
+ * ```
2543
+ */
2544
+ export declare function validatePlan(plan: Plan): Validation;
2545
+
1900
2546
  /** The semantic pass over a blueprint; returns, never throws. */
1901
2547
  export declare interface Validation {
1902
2548
  readonly valid: boolean;
@@ -1904,6 +2550,9 @@ export declare function coreViteConfig(): string;
1904
2550
  readonly warnings: readonly string[];
1905
2551
  }
1906
2552
 
2553
+ /** The exact three-component version syntax accepted by `validateBlueprint`. */
2554
+ export declare const VERSION_PATTERN: RegExp;
2555
+
1907
2556
  /**
1908
2557
  * One dependency's declared `range` against the registry `latest`, plus its
1909
2558
  * `freshness` verdict.
@@ -1921,13 +2570,14 @@ export declare function coreViteConfig(): string;
1921
2570
 
1922
2571
  /**
1923
2572
  * The rendered import / `resolve` header block every `rootViteConfig` shape
1924
- * prefixes — the Playwright import lines + `createBrowserProvider` appear
1925
- * only when `needsPlaywright`, per the three grounded `rootViteConfig`
1926
- * shapes: unconditional for a multi-surface blueprint, conditional on the
1927
- * sole surface being `'browser'` for a single non-`core` surface, absent for
2573
+ * prefixes — the official Playwright provider import appears only when
2574
+ * `needsPlaywright`, per the three grounded `rootViteConfig`
2575
+ * shapes: unconditional for a multi-environment blueprint, conditional on the
2576
+ * sole environment being `'browser'` for a single non-`core` environment, absent for
1928
2577
  * `core`-only.
1929
2578
  *
1930
2579
  * @param needsPlaywright - Whether this shape ships a browser test project (and so needs Playwright).
2580
+ * @param needsVue - Whether the generated root imports the Vue Vite plugin.
1931
2581
  * @returns The rendered header block, newline-terminated.
1932
2582
  *
1933
2583
  * @example
@@ -1936,6 +2586,6 @@ export declare function coreViteConfig(): string;
1936
2586
  * viteHeader(true).includes('@vitest/browser-playwright') // true
1937
2587
  * ```
1938
2588
  */
1939
- export declare function viteHeader(needsPlaywright: boolean): string;
2589
+ export declare function viteHeader(needsPlaywright: boolean, needsVue?: boolean): string;
1940
2590
 
1941
2591
  export { }