@orkestrel/scaffold 0.0.1

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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/bin/scaffold.js +1539 -0
  4. package/dist/bin/scaffold.js.map +1 -0
  5. package/dist/host/AGENTS.md +939 -0
  6. package/dist/host/CLAUDE.md +495 -0
  7. package/dist/host/LICENSE +21 -0
  8. package/dist/host/claude/agents/builder.md +48 -0
  9. package/dist/host/claude/agents/checker.md +37 -0
  10. package/dist/host/claude/agents/composer.md +64 -0
  11. package/dist/host/claude/agents/grok.md +50 -0
  12. package/dist/host/claude/agents/orkestrel.md +236 -0
  13. package/dist/host/claude/agents/planner.md +44 -0
  14. package/dist/host/claude/agents/researcher.md +38 -0
  15. package/dist/host/claude/agents/reviewer.md +47 -0
  16. package/dist/host/claude/agents/scout.md +35 -0
  17. package/dist/host/claude/agents/verifier.md +34 -0
  18. package/dist/host/claude/settings.json +26 -0
  19. package/dist/host/dotfiles/editorconfig +17 -0
  20. package/dist/host/dotfiles/gitattributes +3 -0
  21. package/dist/host/dotfiles/gitignore +40 -0
  22. package/dist/host/dotfiles/oxfmtrc.json +18 -0
  23. package/dist/host/dotfiles/oxlintignore +20 -0
  24. package/dist/host/dotfiles/oxlintrc.json +58 -0
  25. package/dist/host/dotfiles/prettierignore +5 -0
  26. package/dist/host/github/workflows/ci.yml +64 -0
  27. package/dist/host/guides/src/guide.md +312 -0
  28. package/dist/host/guides/src/scaffold.md +2152 -0
  29. package/dist/host/manifest.json +137 -0
  30. package/dist/host/scripts/cursor.sh +74 -0
  31. package/dist/host/scripts/deps.sh +38 -0
  32. package/dist/host/scripts/ollama.sh +163 -0
  33. package/dist/src/core/index.cjs +3728 -0
  34. package/dist/src/core/index.cjs.map +1 -0
  35. package/dist/src/core/index.d.cts +1941 -0
  36. package/dist/src/core/index.d.ts +1941 -0
  37. package/dist/src/core/index.js +3636 -0
  38. package/dist/src/core/index.js.map +1 -0
  39. package/dist/src/server/index.cjs +1595 -0
  40. package/dist/src/server/index.cjs.map +1 -0
  41. package/dist/src/server/index.d.cts +779 -0
  42. package/dist/src/server/index.d.ts +779 -0
  43. package/dist/src/server/index.js +1572 -0
  44. package/dist/src/server/index.js.map +1 -0
  45. package/package.json +113 -0
@@ -0,0 +1,1941 @@
1
+ import { ArrayShape } from '@orkestrel/contract';
2
+ import { BooleanShape } from '@orkestrel/contract';
3
+ import { ContractShape } from '@orkestrel/contract';
4
+ import { EmitterErrorHandler } from '@orkestrel/emitter';
5
+ import { EmitterHooks } from '@orkestrel/emitter';
6
+ import { EmitterInterface } from '@orkestrel/emitter';
7
+ import { Guard } from '@orkestrel/contract';
8
+ import { LiteralShape } from '@orkestrel/contract';
9
+ import { NumberShape } from '@orkestrel/contract';
10
+ import { ObjectShape } from '@orkestrel/contract';
11
+ import { OptionalShape } from '@orkestrel/contract';
12
+ import { StringShape } from '@orkestrel/contract';
13
+ import { TableAlign } from '@orkestrel/markdown';
14
+ import { TemplateDefinition } from '@orkestrel/template';
15
+
16
+ /**
17
+ * Build a formatter-width-aligned GFM table string from header and row cells.
18
+ *
19
+ * @param header - The header cell strings, in column order.
20
+ * @param rows - The body rows, each a list of cell strings matching `header`'s column count.
21
+ * @param align - Optional per-column alignment; defaults every column to `'none'`.
22
+ * @remarks
23
+ * Builds a `TableNode` (each cell parsed with `parseInline`) and serializes it
24
+ * through `renderMarkdown`, which contributes the structure — `\|`-escaping any
25
+ * literal pipe and emitting the alignment delimiter row — at a flat 1-space
26
+ * cell padding. This function then re-pads BOTH the cells AND the delimiter row
27
+ * to per-column codepoint width, matching oxfmt's markdown re-padding.
28
+ * @returns The aligned GFM table string.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * import { alignTable } from '@orkestrel/scaffold'
33
+ *
34
+ * alignTable(['API', 'Kind'], [['`createRouter`', 'function']])
35
+ * // '| API | Kind |\n| --------------- | -------- |\n| `createRouter` | function |'
36
+ * ```
37
+ */
38
+ export declare function alignTable(header: readonly string[], rows: readonly (readonly string[])[], align?: readonly TableAlign[]): string;
39
+
40
+ /**
41
+ * Apply a blueprint's `overrides` over a drafted artifact list — an override
42
+ * 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).
46
+ *
47
+ * @param artifacts - The drafted `Artifact[]`.
48
+ * @param overrides - The blueprint's `overrides`.
49
+ * @returns The artifact list with matching overrides applied.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * applyOverrides(artifacts, [override('README.md', '# custom')])[0].content // '# custom'
54
+ * ```
55
+ */
56
+ export declare function applyOverrides(artifacts: readonly Artifact[], overrides: Blueprint['overrides']): readonly Artifact[];
57
+
58
+ /**
59
+ * One file in a `Plan`.
60
+ *
61
+ * @remarks
62
+ * `content` present for `template` / `computed`, `source` (a host-relative
63
+ * path) for `host`.
64
+ */
65
+ export declare interface Artifact {
66
+ readonly path: string;
67
+ readonly group: Group;
68
+ readonly origin: Origin;
69
+ readonly surface?: Surface;
70
+ readonly content?: string;
71
+ readonly source?: string;
72
+ }
73
+
74
+ /**
75
+ * Build the `Artifact` object shape.
76
+ *
77
+ * @remarks
78
+ * `origin` is a `literalShape(ORIGINS)`; `content` and `source` are both
79
+ * optional (the `origin` axis decides which one a given artifact carries).
80
+ *
81
+ * @returns A fresh `ContractShape` describing one planned file.
82
+ */
83
+ export declare function artifactShape(): ObjectShape<{
84
+ 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>;
89
+ source: OptionalShape<StringShape>;
90
+ }, false>;
91
+
92
+ /**
93
+ * The whole diff of a plan against a target's current content.
94
+ *
95
+ * @remarks
96
+ * A `Compiler.audit` over a gate-failing blueprint sets `complete: false` with
97
+ * the gate's `questions` and zero findings, while `diffPlan` over an existing
98
+ * plan is always `complete: true`.
99
+ */
100
+ export declare interface Audit {
101
+ readonly findings: readonly Finding[];
102
+ readonly clean: boolean;
103
+ readonly complete: boolean;
104
+ readonly questions: readonly Question[];
105
+ readonly drifted: number;
106
+ readonly missing: number;
107
+ readonly foreign: number;
108
+ }
109
+
110
+ /**
111
+ * Project an `Audit` into a markdown drift report.
112
+ *
113
+ * @param audit - The audit to report.
114
+ * @returns Findings grouped by `drift`, `aligned` entries elided — what `repair` will touch.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * import { auditToReview } from '@orkestrel/scaffold'
119
+ *
120
+ * auditToReview(audit) // '# Audit\n\n- clean: false\n…\n## stale\n\n| Path | Group |\n…'
121
+ * ```
122
+ */
123
+ export declare function auditToReview(audit: Audit): string;
124
+
125
+ /** The closed, JSON-serializable package spec. */
126
+ export declare interface Blueprint {
127
+ readonly name: string;
128
+ readonly description?: string;
129
+ readonly keywords: readonly string[];
130
+ readonly surfaces: readonly Surface[];
131
+ readonly dependencies: readonly Dependency[];
132
+ /** Runtime `@orkestrel/*` peers, emitted as `peerDependencies` — a peer flagged `optional` also gets a `peerDependenciesMeta` entry. */
133
+ readonly peers: readonly Dependency[];
134
+ /** Package-specific `devDependencies` merged into the generated uniform baseline — the middleware pattern of shipping `@orkestrel/{database,router,server}` for its tests. */
135
+ readonly extras: readonly Dependency[];
136
+ readonly version: string;
137
+ readonly engines: string;
138
+ readonly overrides: readonly Override[];
139
+ }
140
+
141
+ /**
142
+ * Build a fresh `Blueprint` from a name and a partial of the rest.
143
+ *
144
+ * @param name - The package name.
145
+ * @param options - A partial of the remaining `Blueprint` fields.
146
+ * @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.
151
+ * @returns A complete `Blueprint`.
152
+ *
153
+ * @example
154
+ * ```ts
155
+ * import { blueprint } from '@orkestrel/scaffold'
156
+ *
157
+ * blueprint('router').version // '0.0.1'
158
+ * ```
159
+ */
160
+ export declare function blueprint(name: string, options?: Partial<Omit<Blueprint, 'name'>>): Blueprint;
161
+
162
+ /**
163
+ * Build the `Blueprint` object shape.
164
+ *
165
+ * @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`.
172
+ *
173
+ * @returns A fresh `ContractShape` describing the closed `Blueprint` spec.
174
+ */
175
+ export declare function blueprintShape(): ObjectShape<{
176
+ name: StringShape;
177
+ description: OptionalShape<StringShape>;
178
+ keywords: ArrayShape<StringShape>;
179
+ surfaces: ArrayShape<LiteralShape<readonly ["core", "browser", "server"]>>;
180
+ dependencies: ArrayShape<ObjectShape<{
181
+ name: StringShape;
182
+ range: StringShape;
183
+ optional: OptionalShape<BooleanShape>;
184
+ }, false>>;
185
+ peers: ArrayShape<ObjectShape<{
186
+ name: StringShape;
187
+ range: StringShape;
188
+ optional: OptionalShape<BooleanShape>;
189
+ }, false>>;
190
+ extras: ArrayShape<ObjectShape<{
191
+ name: StringShape;
192
+ range: StringShape;
193
+ optional: OptionalShape<BooleanShape>;
194
+ }, false>>;
195
+ version: StringShape;
196
+ engines: StringShape;
197
+ overrides: ArrayShape<ObjectShape<{
198
+ path: StringShape;
199
+ content: StringShape;
200
+ }, false>>;
201
+ }, false>;
202
+
203
+ /**
204
+ * Derive the declared public `Member[]` from a blueprint.
205
+ *
206
+ * @param spec - The blueprint to derive members from.
207
+ * @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.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * import { blueprint, blueprintToMembers } from '@orkestrel/scaffold'
218
+ *
219
+ * blueprintToMembers(blueprint('router'))[0] // { name: 'Router', category: 'entity', … }
220
+ * ```
221
+ */
222
+ export declare function blueprintToMembers(spec: Blueprint): readonly Member[];
223
+
224
+ /**
225
+ * The full pure compilation: draft a blueprint's artifacts — the manifest and
226
+ * exports combination rules over the per-surface `SURFACE_MATRIX` rows, plus
227
+ * `HOST_PATHS` and `overrides` — then pin.
228
+ *
229
+ * @param blueprint - The `Blueprint` to compile.
230
+ * @param groups - An optional `Group[]` selection (default: all groups).
231
+ * @returns The drafted, pinned `Plan`.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * const plan = blueprintToPlan(blueprint('router', { surfaces: ['core'] }))
236
+ * plan.artifacts.length // every file the package needs
237
+ * ```
238
+ */
239
+ export declare function blueprintToPlan(blueprint: Blueprint, groups?: readonly Group[]): Plan;
240
+
241
+ /**
242
+ * One fleet package's catalog row — the `orkestrel` agent's package-catalog
243
+ * section, derived rather than hand-maintained.
244
+ *
245
+ * @remarks
246
+ * `description` is the flattened text of the package's own guide's FIRST
247
+ * blockquote; empty (`''`) when that guide is missing, unreadable, or
248
+ * carries no blockquote — never a placeholder string.
249
+ */
250
+ export declare interface CatalogEntry {
251
+ readonly name: string;
252
+ readonly version: string;
253
+ readonly description: string;
254
+ }
255
+
256
+ /**
257
+ * Extract the `@orkestrel/<name>` package names from a catalog markdown
258
+ * block/table, in row order.
259
+ *
260
+ * @param text - The markdown block/table text (the `orkestrel.md` embedded
261
+ * catalog shape — GFM table rows opening `| @orkestrel/<name>`).
262
+ * @remarks
263
+ * Pure line-scan: a row matches when, after trimming, it starts with
264
+ * `| @orkestrel/` followed by a `NAME_PATTERN`-shaped short name and a cell
265
+ * boundary (`|` or whitespace) — the same row shape `runCatalog`'s shrink
266
+ * count previously matched inline; this is the single source both consume.
267
+ * Returns `[]` when the text has no markers/rows (never throws).
268
+ * @returns The full `@orkestrel/<name>` names found, in order.
269
+ *
270
+ * @example
271
+ * ```ts
272
+ * import { catalogNames } from '@orkestrel/scaffold'
273
+ *
274
+ * catalogNames('| @orkestrel/contract | ... |\n| @orkestrel/emitter | ... |')
275
+ * // ['@orkestrel/contract', '@orkestrel/emitter']
276
+ * ```
277
+ */
278
+ export declare function catalogNames(text: string): readonly string[];
279
+
280
+ /**
281
+ * Project a fleet package catalog into a markdown table — the block
282
+ * `.claude/agents/orkestrel.md`'s catalog markers wrap.
283
+ *
284
+ * @param entries - The catalog rows to render.
285
+ * @remarks
286
+ * 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.
290
+ * @returns The aligned GFM table string.
291
+ *
292
+ * @example
293
+ * ```ts
294
+ * import { catalogToBlock } from '@orkestrel/scaffold'
295
+ *
296
+ * catalogToBlock([
297
+ * { name: '@orkestrel/router', version: '0.0.5', description: 'A tiny hash-router.' },
298
+ * { name: '@orkestrel/contract', version: '0.0.5', description: '' },
299
+ * ])
300
+ * // '| Package | Version | Description |\n| … |\n| @orkestrel/contract | 0.0.5 | — |\n…'
301
+ * ```
302
+ */
303
+ export declare function catalogToBlock(entries: readonly CatalogEntry[]): string;
304
+
305
+ /** The four `Category` values, frozen. */
306
+ export declare const CATEGORIES: readonly ["type", "constant", "factory", "entity"];
307
+
308
+ /** What a declared `Member` IS in the scaffolded surface. */
309
+ export declare type Category = 'type' | 'constant' | 'factory' | 'entity';
310
+
311
+ /**
312
+ * A code-unit (not locale-sensitive) comparator — matches the `keywords` sort
313
+ * and keeps ordering stable across locales/environments.
314
+ *
315
+ * @param a - The first string.
316
+ * @param b - The second string.
317
+ * @returns `-1` / `0` / `1` per code-unit order.
318
+ *
319
+ * @example
320
+ * ```ts
321
+ * [...['b', 'a']].sort(compareCodeUnit) // ['a', 'b']
322
+ * ```
323
+ */
324
+ export declare function compareCodeUnit(a: string, b: string): number;
325
+
326
+ /** The pipeline phases in order, frozen. */
327
+ export declare const COMPILE_STAGES: readonly ["draft", "gate", "pin"];
328
+
329
+ /** A visible marker for a stage that failed. */
330
+ export declare interface CompileFailure {
331
+ readonly stage: CompileStage;
332
+ readonly code: ScaffoldErrorCode;
333
+ readonly message: string;
334
+ }
335
+
336
+ /**
337
+ * The compilation orchestrator — runs the fixed three-stage `[draft, gate,
338
+ * pin]` pipeline over a `Blueprint` and the pure `audit` projection, owning a
339
+ * typed `emitter` (AGENTS §13).
340
+ *
341
+ * @remarks
342
+ * `compile` and `audit` are genuinely synchronous and pure; the gate fails
343
+ * CLOSED — a blueprint failing `validateBlueprint`, or carrying an override
344
+ * that matches no planned artifact or targets a `host`-origin path, yields a
345
+ * visible incomplete `Scaffolding` (`plan` absent, `questions` populated)
346
+ * rather than throwing. A dependency outside the vendored guide set surfaces
347
+ * a non-blocking `Question` and a `host`-origin pointer artifact instead of a
348
+ * fabricated mirror. `compile` emits `compile` only for a complete
349
+ * compilation and `block` for a gated one; `audit` emits `block` (when gated)
350
+ * then `audit`, never `compile`. After `destroy()` every method but the
351
+ * getter and `destroy` itself throws `ScaffoldError('DESTROYED', …)`.
352
+ *
353
+ * @example
354
+ * ```ts
355
+ * import { blueprint, Compiler } from '@src/core'
356
+ *
357
+ * const compiler = new Compiler()
358
+ * const scaffolding = compiler.compile(blueprint('router', { surfaces: ['core'] }))
359
+ * scaffolding.complete // true
360
+ * compiler.destroy()
361
+ * ```
362
+ */
363
+ export declare class Compiler implements CompilerInterface {
364
+ #private;
365
+ constructor(options?: CompilerOptions);
366
+ get emitter(): EmitterInterface<CompilerEventMap>;
367
+ /**
368
+ * Run the three-stage pipeline over a `Blueprint`, returning a complete or
369
+ * visible-incomplete `Scaffolding`.
370
+ *
371
+ * @param blueprint - The `Blueprint` to compile.
372
+ * @param groups - Optional `Group` selection scoping the plan to those
373
+ * artifact groups; absent means the full plan.
374
+ * @returns The `Scaffolding` outcome of this compile.
375
+ *
376
+ * @example
377
+ * ```ts
378
+ * const scaffolding = compiler.compile(blueprint('timeout', { surfaces: ['core'] }))
379
+ * scaffolding.stages.map((record) => record.stage) // ['draft', 'gate', 'pin']
380
+ * ```
381
+ */
382
+ compile(blueprint: Blueprint, groups?: readonly Group[]): Scaffolding;
383
+ /**
384
+ * Compile the blueprint, then diff the resulting plan against the
385
+ * caller-supplied current target content.
386
+ *
387
+ * @param blueprint - The `Blueprint` to compile and audit.
388
+ * @param current - The target's current content, keyed by artifact path.
389
+ * @param groups - Optional `Group` selection scoping the audit to those
390
+ * artifact groups; absent means the full plan.
391
+ * @returns The `Audit` outcome — a gated blueprint returns `complete: false`
392
+ * with the gate's blocking `questions` and zero findings.
393
+ *
394
+ * @example
395
+ * ```ts
396
+ * const audit = compiler.audit(blueprint('timeout', { surfaces: ['core'] }), {})
397
+ * audit.missing // every artifact — nothing exists at the target yet
398
+ * ```
399
+ */
400
+ audit(blueprint: Blueprint, current: Readonly<Record<string, string>>, groups?: readonly Group[]): Audit;
401
+ /** Idempotent teardown — emits `destroy`, then destroys the emitter LAST. */
402
+ destroy(): void;
403
+ }
404
+
405
+ /** The default id for a `Compiler` orchestrator. */
406
+ export declare const COMPILER_ID = "compiler";
407
+
408
+ /** A structured input/output snapshot of one pipeline phase. */
409
+ export declare interface CompileRecord {
410
+ readonly stage: CompileStage;
411
+ readonly input: unknown;
412
+ readonly output: unknown;
413
+ readonly failed: boolean;
414
+ readonly error?: string;
415
+ }
416
+
417
+ /** `Compiler`'s push observation surface (AGENTS §13). */
418
+ export declare type CompilerEventMap = {
419
+ readonly compile: readonly [scaffolding: Scaffolding];
420
+ readonly audit: readonly [audit: Audit];
421
+ readonly block: readonly [questions: readonly Question[]];
422
+ readonly error: readonly [error: unknown];
423
+ readonly destroy: readonly [];
424
+ };
425
+
426
+ /** The compilation orchestrator contract. */
427
+ export declare interface CompilerInterface {
428
+ readonly emitter: EmitterInterface<CompilerEventMap>;
429
+ compile(blueprint: Blueprint, groups?: readonly Group[]): Scaffolding;
430
+ audit(blueprint: Blueprint, current: Readonly<Record<string, string>>, groups?: readonly Group[]): Audit;
431
+ destroy(): void;
432
+ }
433
+
434
+ /** Options for `createCompiler` / the `Compiler` constructor. */
435
+ export declare interface CompilerOptions {
436
+ readonly on?: EmitterHooks<CompilerEventMap>;
437
+ readonly error?: EmitterErrorHandler;
438
+ }
439
+
440
+ /** The three fixed pipeline phases, in order. */
441
+ export declare type CompileStage = 'draft' | 'gate' | 'pin';
442
+
443
+ /**
444
+ * Compute a canonical FNV-1a digest of a text string.
445
+ *
446
+ * @param text - The text to digest.
447
+ * @remarks
448
+ * The 32-bit FNV-1a offset basis/prime, `Math.imul` for the wraparound
449
+ * multiply, rendered as an 8-hex-digit zero-padded lowercase string —
450
+ * deterministic, no clocks or randomness.
451
+ * @returns The 8-hex-digit FNV-1a digest of `text`.
452
+ *
453
+ * @example
454
+ * ```ts
455
+ * import { computeHash } from '@orkestrel/scaffold'
456
+ *
457
+ * computeHash('hello-world') // '428d118e'
458
+ * ```
459
+ */
460
+ export declare function computeHash(text: string): string;
461
+
462
+ /**
463
+ * Draft the `configs` group's `computed` artifacts — the root
464
+ * `tsconfig.json` / `vite.config.ts` plus each declared surface's
465
+ * `configs/src/*` pair, grounded against the live middleware (core+server)
466
+ * and router (core+browser+server) exemplars.
467
+ *
468
+ * @param spec - The `Blueprint` to derive config artifacts from.
469
+ * @returns The `configs` group's `Artifact[]`.
470
+ *
471
+ * @example
472
+ * ```ts
473
+ * configArtifacts(blueprint('router')).length // 4
474
+ * ```
475
+ */
476
+ export declare function configArtifacts(spec: Blueprint): readonly Artifact[];
477
+
478
+ /**
479
+ * `configs/src/tsconfig.core.json` — unchanged core shape.
480
+ *
481
+ * @returns The core surface `tsconfig` file content, newline-terminated.
482
+ *
483
+ * @example
484
+ * ```ts
485
+ * coreTsconfig().includes('"rootDir": "../../src/core"') // true
486
+ * ```
487
+ */
488
+ export declare function coreTsconfig(): string;
489
+
490
+ /**
491
+ * `configs/src/vite.core.config.ts` — inlines its own `build.lib` /
492
+ * `rollupOptions` (core's `srcCore` root export carries no build.lib).
493
+ *
494
+ * @returns The core surface `vite.config.ts` file content, newline-terminated.
495
+ *
496
+ * @example
497
+ * ```ts
498
+ * coreViteConfig().includes('srcCore(') // true
499
+ * ```
500
+ */
501
+ export declare function coreViteConfig(): string;
502
+
503
+ /**
504
+ * Validate and return a `Blueprint` from plain data.
505
+ *
506
+ * @param data - A `name` plus a partial of the remaining `Blueprint` fields.
507
+ * @remarks
508
+ * Fills the builder defaults, then checks BOTH the exact-record shape
509
+ * (`isBlueprint`) and the semantic pass (`validateBlueprint`) — so an
510
+ * off-`NAME_PATTERN` name throws here too.
511
+ * @returns The validated `Blueprint`.
512
+ * @throws {@link ScaffoldError} coded `INVALID` when the structure or the
513
+ * semantic pass fails.
514
+ *
515
+ * @example
516
+ * ```ts
517
+ * import { createBlueprint } from '@src/core'
518
+ *
519
+ * createBlueprint({ name: 'Router', surfaces: [] }) // throws ScaffoldError('INVALID', …)
520
+ * ```
521
+ */
522
+ export declare function createBlueprint(data: Partial<Blueprint> & {
523
+ readonly name: string;
524
+ }): Blueprint;
525
+
526
+ /**
527
+ * Create a `CompilerInterface` — the compilation orchestrator.
528
+ *
529
+ * @param options - `CompilerOptions` — `on` initial event listeners, `error` the listener-error handler.
530
+ * @returns A fresh `Compiler`.
531
+ *
532
+ * @example
533
+ * ```ts
534
+ * import { createCompiler } from '@src/core'
535
+ *
536
+ * const compiler = createCompiler()
537
+ * compiler.destroy()
538
+ * ```
539
+ */
540
+ export declare function createCompiler(options?: CompilerOptions): CompilerInterface;
541
+
542
+ /**
543
+ * Create a working `PlanManagerInterface`.
544
+ *
545
+ * @param options - `PlanManagerOptions` — `plans` to seed the registry, `on` / `error` for the emitter.
546
+ * @returns A fresh `PlanManager`.
547
+ *
548
+ * @example
549
+ * ```ts
550
+ * import { createPlanManager } from '@src/core'
551
+ *
552
+ * const plans = createPlanManager()
553
+ * plans.size // 0
554
+ * plans.destroy()
555
+ * ```
556
+ */
557
+ export declare function createPlanManager(options?: PlanManagerOptions): PlanManagerInterface;
558
+
559
+ /** The `engines.node` range the `blueprint` builder fills. */
560
+ export declare const DEFAULT_ENGINES = ">=22";
561
+
562
+ /** The starting version the `blueprint` builder fills. */
563
+ export declare const DEFAULT_VERSION = "0.0.1";
564
+
565
+ /**
566
+ * Build one delimiter-row cell for a GFM table column.
567
+ *
568
+ * @param columnAlign - The column's `TableAlign`.
569
+ * @param width - The column's codepoint width.
570
+ * @remarks
571
+ * `'left'` prefixes `:`, `'right'` suffixes `:`, `'center'` wraps both ends,
572
+ * `'none'` is plain dashes — one dash per width unit, `:` markers consuming
573
+ * a dash slot rather than adding to `width`.
574
+ * @returns The delimiter cell string for this column.
575
+ *
576
+ * @example
577
+ * ```ts
578
+ * import { delimiterCell } from '@orkestrel/scaffold'
579
+ *
580
+ * delimiterCell('left', 5) // ':----'
581
+ * ```
582
+ */
583
+ export declare function delimiterCell(columnAlign: TableAlign, width: number): string;
584
+
585
+ /**
586
+ * One runtime `@orkestrel/*` dependency.
587
+ *
588
+ * @remarks
589
+ * Drives its `package.json` entry, the build externals, and its
590
+ * `guides/src/<dep>.md` mirror — byte-correct for a dep this package vendors
591
+ * (contract / emitter / markdown / template / terminal / console / guide),
592
+ * a `host`-origin pointer the caller syncs otherwise.
593
+ */
594
+ export declare interface Dependency {
595
+ readonly name: string;
596
+ readonly range: string;
597
+ /** Meaningful only when this `Dependency` appears in a `Blueprint`'s `peers` — `true` emits a `peerDependenciesMeta` `{ optional: true }` entry alongside it. */
598
+ readonly optional?: boolean;
599
+ }
600
+
601
+ /**
602
+ * Build a fresh `Dependency`.
603
+ *
604
+ * @param name - The `@orkestrel/*` package name.
605
+ * @param range - The semver range.
606
+ * @param optional - Whether this dependency is optional; meaningful only when
607
+ * used as a `Blueprint` peer. Omitted entirely when absent.
608
+ * @returns A `Dependency` with `name` / `range` set, `optional` included only when passed.
609
+ *
610
+ * @example
611
+ * ```ts
612
+ * import { dependency } from '@orkestrel/scaffold'
613
+ *
614
+ * dependency('@orkestrel/contract', '^0.0.5') // { name: '@orkestrel/contract', range: '^0.0.5' }
615
+ * dependency('@orkestrel/database', '^0.0.5', true) // optional: true
616
+ * ```
617
+ */
618
+ export declare function dependency(name: string, range: string, optional?: boolean): Dependency;
619
+
620
+ /**
621
+ * The `@orkestrel/*` dependency-name RegExp — every `Dependency.name` must be
622
+ * scoped to `@orkestrel` and NAME_PATTERN-shaped after the scope, closing the
623
+ * traversal vector a hand-built `../`-laced name would open through
624
+ * `Compiler.#pointerArtifacts`' `guides/src/<short>.md` path derivation.
625
+ */
626
+ export declare const DEPENDENCY_NAME_PATTERN: RegExp;
627
+
628
+ /**
629
+ * Build the `Dependency` object shape.
630
+ *
631
+ * @returns A fresh `ContractShape` describing `{ name, range, optional? }`.
632
+ */
633
+ export declare function dependencyShape(): ObjectShape<{
634
+ name: StringShape;
635
+ range: StringShape;
636
+ optional: OptionalShape<BooleanShape>;
637
+ }, false>;
638
+
639
+ /**
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.
646
+ *
647
+ * @param extras - The blueprint's package-specific `extras` `Dependency[]`.
648
+ * @returns The merged `devDependencies` record.
649
+ *
650
+ * @example
651
+ * ```ts
652
+ * devDependenciesFor([])['typescript'] // '^6.0.3'
653
+ * ```
654
+ */
655
+ export declare function devDependenciesFor(extras: readonly Dependency[]): Readonly<Record<string, string>>;
656
+
657
+ /**
658
+ * Diff a plan's artifacts against a target's current content.
659
+ *
660
+ * @param plan - The plan whose artifacts are the source of truth.
661
+ * @param current - The target's current content, keyed by artifact-relative path.
662
+ * @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.
671
+ * @returns The `Audit` of drift findings — pure, no I/O.
672
+ *
673
+ * @example
674
+ * ```ts
675
+ * import { diffPlan } from '@orkestrel/scaffold'
676
+ *
677
+ * diffPlan(plan, current) // { findings: [...], clean: false, complete: true, drifted: 1, missing: 20, foreign: 0 }
678
+ * ```
679
+ */
680
+ export declare function diffPlan(plan: Plan, current: Readonly<Record<string, string>>): Audit;
681
+
682
+ /** One `Finding`'s verdict against the target's current content. */
683
+ export declare type Drift = 'aligned' | 'stale' | 'missing' | 'foreign';
684
+
685
+ /**
686
+ * One dual-format (`import` + `require`) `exports` condition block.
687
+ *
688
+ * @param path - The extensionless dist path to point both conditions at.
689
+ * @returns The dual `import`/`require` exports condition object.
690
+ *
691
+ * @example
692
+ * ```ts
693
+ * dualCondition('./dist/src/core/index')
694
+ * // { import: { types: '….d.ts', default: '….js' }, require: { types: '….d.cts', default: '….cjs' } }
695
+ * ```
696
+ */
697
+ export declare function dualCondition(path: string): Readonly<Record<string, unknown>>;
698
+
699
+ /**
700
+ * Build the `main` / `module` / top-level `types` entry fields.
701
+ *
702
+ * @param surfaces - The declared `Surface[]`.
703
+ * @returns The `package.json` `main` / `module` / optional `types` fields.
704
+ *
705
+ * @example
706
+ * ```ts
707
+ * entryFields(['browser']).main // './dist/src/browser/index.js'
708
+ * ```
709
+ */
710
+ export declare function entryFields(surfaces: readonly Surface[]): {
711
+ readonly main: string;
712
+ readonly module: string;
713
+ readonly types?: string;
714
+ };
715
+
716
+ /**
717
+ * Build the `package.json` `exports` map.
718
+ *
719
+ * @param surfaces - The declared `Surface[]`.
720
+ * @returns The `package.json` `exports` map.
721
+ *
722
+ * @example
723
+ * ```ts
724
+ * exportsMap(['core'])['.'] // dual import/require condition block
725
+ * ```
726
+ */
727
+ export declare function exportsMap(surfaces: readonly Surface[]): Readonly<Record<string, unknown>>;
728
+
729
+ /**
730
+ * The `extras` dependency-name RegExp — a strict npm package-name shape: an
731
+ * optional single `@scope/` prefix, then lowercase letters, digits, hyphens,
732
+ * dots, and underscores (never leading, never adjacent to the scope slash).
733
+ * Broader than `DEPENDENCY_NAME_PATTERN` on purpose: `extras` names are
734
+ * manifest-content only (`devDependenciesFor` keys `devDependencies` with
735
+ * them, `Compiler.#pointerArtifacts` never reads them for a path), so they
736
+ * carry no traversal vector — no `..`, no backslash, and the single optional
737
+ * `/` is fixed to the one scope boundary, so the shape stays structurally
738
+ * incapable of escaping a derived path even though it accepts any valid npm
739
+ * package name (unscoped or externally-scoped), not just `@orkestrel/*`.
740
+ */
741
+ export declare const EXTRA_NAME_PATTERN: RegExp;
742
+
743
+ /**
744
+ * 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).
747
+ *
748
+ * @param path - The artifact's output path.
749
+ * @param group - The artifact's `Group`.
750
+ * @param id - The `TEMPLATES` entry id to fill.
751
+ * @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.
753
+ * @returns The filled `template`-origin `Artifact`.
754
+ *
755
+ * @example
756
+ * ```ts
757
+ * fillArtifact('README.md', 'docs', 'readme', { name: 'router', pascal: 'Router' })
758
+ * // { path: 'README.md', group: 'docs', origin: 'template', content: '# router\n…' }
759
+ * ```
760
+ */
761
+ export declare function fillArtifact(path: string, group: Group, id: string, values: Readonly<Record<string, unknown>>, surface?: Surface): Artifact;
762
+
763
+ /** One audit drift result. */
764
+ export declare interface Finding {
765
+ readonly path: string;
766
+ readonly group: Group;
767
+ readonly drift: Drift;
768
+ }
769
+
770
+ /** The four `Freshness` values, frozen — the currency axis `Sync` reports on. */
771
+ export declare const FRESHNESS: readonly ["current", "behind", "missing", "failed"];
772
+
773
+ /**
774
+ * One `GuideSync` / `VersionSync`'s currency against upstream.
775
+ *
776
+ * @remarks
777
+ * `missing` is an upstream `404`; `failed` is a transport fault.
778
+ */
779
+ export declare type Freshness = 'current' | 'behind' | 'missing' | 'failed';
780
+
781
+ /** The closed artifact-group vocabulary a plan selects over. */
782
+ export declare type Group = 'manifest' | 'configs' | 'source' | 'tests' | 'guides' | 'docs' | 'orchestration';
783
+
784
+ /** The seven `Group` values, frozen — the artifact-group selection vocabulary. */
785
+ export declare const GROUPS: readonly ["manifest", "configs", "source", "tests", "guides", "docs", "orchestration"];
786
+
787
+ /**
788
+ * Draft the `guides` group's artifacts — the package's own filled guide stub,
789
+ * the guides index, and any vendored dependency guide mirrors.
790
+ *
791
+ * @param spec - The `Blueprint` to derive guide artifacts from.
792
+ * @param pascal - The package's PascalCase entity name.
793
+ * @param members - The blueprint's derived `Member[]`.
794
+ * @returns The `guides` group's `Artifact[]`.
795
+ *
796
+ * @example
797
+ * ```ts
798
+ * guideArtifacts(blueprint('router'), 'Router', blueprintToMembers(blueprint('router'))).length // 2
799
+ * ```
800
+ */
801
+ export declare function guideArtifacts(spec: Blueprint, pascal: string, members: readonly Member[]): readonly Artifact[];
802
+
803
+ /**
804
+ * 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.
809
+ *
810
+ * @param category - The `Member['category']` to filter rows by.
811
+ * @param members - The blueprint's derived `Member[]` (previously closed over by the caller).
812
+ * @returns The aligned markdown table for the category's deduped members.
813
+ *
814
+ * @example
815
+ * ```ts
816
+ * guideMemberTable('entity', blueprintToMembers(blueprint('router'))).includes('Router') // true
817
+ * ```
818
+ */
819
+ export declare function guideMemberTable(category: Member['category'], members: readonly Member[]): string;
820
+
821
+ /**
822
+ * One dependency guide fetched from upstream at its `path`, plus its
823
+ * `freshness` verdict against the local mirror.
824
+ *
825
+ * @remarks
826
+ * `note` carries the failure/anomaly CAUSE — a transport error message, an
827
+ * `HTTP <status>`, `redirected (redirect following is disabled)`, or a
828
+ * `response exceeded limit (<n> bytes)` — present on every non-`current`
829
+ * outcome that has a discoverable cause; absent on `current` and on `behind`
830
+ * (both are clean outcomes with nothing to explain).
831
+ */
832
+ export declare interface GuideSync {
833
+ readonly name: string;
834
+ readonly path: string;
835
+ readonly content: string;
836
+ readonly freshness: Freshness;
837
+ readonly note?: string;
838
+ }
839
+
840
+ /**
841
+ * The byte-copied host artifact paths, frozen.
842
+ *
843
+ * @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
849
+ * scaffold engine's own self-guide (`guides/src/scaffold.md`).
850
+ */
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"];
852
+
853
+ /**
854
+ * Resolve the `Group` a byte-copied `HOST_PATHS` entry belongs to.
855
+ *
856
+ * @param path - A `HOST_PATHS` entry.
857
+ * @returns The owning `Group`.
858
+ *
859
+ * @example
860
+ * ```ts
861
+ * hostGroup('AGENTS.md') // 'docs'
862
+ * hostGroup('.claude') // 'orchestration'
863
+ * ```
864
+ */
865
+ export declare function hostGroup(path: string): Group;
866
+
867
+ /**
868
+ * Infer a foreign path's `Group` from its leading path segment.
869
+ *
870
+ * @param path - The target-relative path to classify.
871
+ * @remarks
872
+ * 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'`.
876
+ * @returns The inferred `Group` for `path`.
877
+ *
878
+ * @example
879
+ * ```ts
880
+ * import { inferGroup } from '@orkestrel/scaffold'
881
+ *
882
+ * inferGroup('src/core/index.ts') // 'source'
883
+ * inferGroup('mystery.config.ts') // 'configs'
884
+ * ```
885
+ */
886
+ export declare function inferGroup(path: string): Group;
887
+
888
+ /**
889
+ * Narrow a value to an `Artifact` — `group` / `origin` on-vocabulary.
890
+ *
891
+ * @remarks
892
+ * Compiled from {@link artifactShape} via `createContract` (AGENTS §14) — a
893
+ * total `Guard`, adversarial input returns `false`, never throws.
894
+ */
895
+ export declare const isArtifact: Guard<Artifact>;
896
+
897
+ /**
898
+ * Test whether a `Freshness` verdict counts toward "behind".
899
+ *
900
+ * @param freshness - The freshness verdict to test.
901
+ * @returns `true` iff `freshness` is `'behind'`.
902
+ *
903
+ * @example
904
+ * ```ts
905
+ * import { isBehind } from '@orkestrel/scaffold'
906
+ *
907
+ * isBehind('behind') // true
908
+ * isBehind('current') // false
909
+ * ```
910
+ */
911
+ export declare function isBehind(freshness: Freshness): boolean;
912
+
913
+ /**
914
+ * Narrow a value to a `Blueprint` — `surfaces` on-vocabulary and non-empty,
915
+ * `name` a non-empty string.
916
+ *
917
+ * @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.
922
+ */
923
+ export declare const isBlueprint: Guard<Blueprint>;
924
+
925
+ /**
926
+ * Narrow a value to a `Dependency` — `name` and `range` non-empty strings.
927
+ *
928
+ * @remarks
929
+ * Compiled from {@link dependencyShape} via `createContract` (AGENTS §14) — a
930
+ * total `Guard`, adversarial input returns `false`, never throws.
931
+ */
932
+ export declare const isDependency: Guard<Dependency>;
933
+
934
+ /**
935
+ * Narrow a value to a `Member` — `category` and `surface` on-vocabulary.
936
+ *
937
+ * @remarks
938
+ * Compiled from {@link memberShape} via `createContract` (AGENTS §14) — a
939
+ * total `Guard`, adversarial input returns `false`, never throws.
940
+ */
941
+ export declare const isMember: Guard<Member>;
942
+
943
+ /**
944
+ * Narrow a value to an `Override` — `path` and `content` non-empty strings.
945
+ *
946
+ * @remarks
947
+ * Compiled from {@link overrideShape} via `createContract` (AGENTS §14) — a
948
+ * total `Guard`, adversarial input returns `false`, never throws.
949
+ */
950
+ export declare const isOverride: Guard<Override>;
951
+
952
+ /**
953
+ * Narrow a value to a `Plan` — the whole exact-record contract, section
954
+ * guards composed.
955
+ *
956
+ * @remarks
957
+ * Compiled from {@link planShape} via `createContract` (AGENTS §14) — a
958
+ * total `Guard`, adversarial input returns `false`, never throws.
959
+ */
960
+ export declare const isPlan: Guard<Plan>;
961
+
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>;
978
+
979
+ /**
980
+ * Narrow a caught value to a `ScaffoldError`.
981
+ *
982
+ * @param value - The caught value to narrow.
983
+ * @returns `true` when `value` is a {@link ScaffoldError}.
984
+ *
985
+ * @example
986
+ * ```ts
987
+ * import { isScaffoldError } from '@orkestrel/scaffold'
988
+ *
989
+ * isScaffoldError(new Error('plain')) // false
990
+ * ```
991
+ */
992
+ export declare function isScaffoldError(value: unknown): value is ScaffoldError;
993
+
994
+ /**
995
+ * Narrow a value to a `SyncReport` — the whole exact-record sync contract,
996
+ * `guide` / `version` sections composed.
997
+ *
998
+ * @remarks
999
+ * Compiled from {@link syncReportShape} via `createContract` (AGENTS §14) — a
1000
+ * total `Guard`, adversarial input returns `false`, never throws.
1001
+ */
1002
+ export declare const isSyncReport: Guard<SyncReport>;
1003
+
1004
+ /**
1005
+ * Parse a `package.json` text into its declared `@orkestrel/*` dependencies.
1006
+ *
1007
+ * @param manifestText - The `package.json` file content.
1008
+ * @remarks
1009
+ * Reads `dependencies`, `devDependencies`, and `peerDependencies` (ALL three,
1010
+ * in that order), keeps only `DEPENDENCY_NAME_PATTERN`-shaped names,
1011
+ * deduplicated (first occurrence wins). Malformed JSON, a non-object root, or
1012
+ * a non-object/non-string section entry is skipped, never thrown.
1013
+ * @returns The declared `Dependency[]` — pure, never throws.
1014
+ *
1015
+ * @example
1016
+ * ```ts
1017
+ * import { manifestToDependencies } from '@orkestrel/scaffold'
1018
+ *
1019
+ * manifestToDependencies('{"dependencies":{"@orkestrel/contract":"^0.0.5"}}')
1020
+ * // [{ name: '@orkestrel/contract', range: '^0.0.5' }]
1021
+ * ```
1022
+ */
1023
+ export declare function manifestToDependencies(manifestText: string): readonly Dependency[];
1024
+
1025
+ /** One declared public export of the scaffolded package; derived by `blueprintToMembers`, never authored. */
1026
+ export declare interface Member {
1027
+ readonly name: string;
1028
+ readonly category: Category;
1029
+ readonly summary: string;
1030
+ readonly surface: Surface;
1031
+ }
1032
+
1033
+ /**
1034
+ * Build a fresh `Member`.
1035
+ *
1036
+ * @param name - The declared export name.
1037
+ * @param category - The `Member`'s `Category`.
1038
+ * @param summary - A one-line description.
1039
+ * @param surface - The owning `Surface`; defaults `'core'`.
1040
+ * @returns A `Member` with every field set.
1041
+ *
1042
+ * @example
1043
+ * ```ts
1044
+ * import { member } from '@orkestrel/scaffold'
1045
+ *
1046
+ * member('RouterOptions', 'type', 'Options for creating a Router.') // surface: 'core'
1047
+ * ```
1048
+ */
1049
+ export declare function member(name: string, category: Category, summary: string, surface?: Surface): Member;
1050
+
1051
+ /**
1052
+ * Build the `Member` object shape.
1053
+ *
1054
+ * @returns A fresh `ContractShape` describing `{ name, category, summary, surface }`.
1055
+ */
1056
+ export declare function memberShape(): ObjectShape<{
1057
+ name: StringShape;
1058
+ category: LiteralShape<readonly ["type", "constant", "factory", "entity"]>;
1059
+ summary: StringShape;
1060
+ surface: LiteralShape<readonly ["core", "browser", "server"]>;
1061
+ }, false>;
1062
+
1063
+ /** The package-name RegExp — lowercase alphanumeric-with-hyphens, letter-first. */
1064
+ export declare const NAME_PATTERN: RegExp;
1065
+
1066
+ /**
1067
+ * How an `Artifact`'s content is produced: `host` byte-copied from the vendored
1068
+ * data root, `template` filled from a frozen `TemplateDefinition` by
1069
+ * `@orkestrel/template`'s pure fill engine, `computed` derived by the core's
1070
+ * own combination logic.
1071
+ */
1072
+ export declare type Origin = 'host' | 'template' | 'computed';
1073
+
1074
+ /** The three `Origin` values, frozen. */
1075
+ export declare const ORIGINS: readonly ["host", "template", "computed"];
1076
+
1077
+ /**
1078
+ * One caller template override.
1079
+ *
1080
+ * @remarks
1081
+ * `content` REPLACES the rendered artifact at `path`, never partially merges.
1082
+ * An override whose `path` matches no planned artifact, or targets a
1083
+ * `host`-origin path, is a BLOCKING question — never a silent add.
1084
+ */
1085
+ export declare interface Override {
1086
+ readonly path: string;
1087
+ readonly content: string;
1088
+ }
1089
+
1090
+ /**
1091
+ * Build a fresh `Override`.
1092
+ *
1093
+ * @param path - The artifact-relative path the override replaces.
1094
+ * @param content - The replacement content.
1095
+ * @returns An `Override` with both fields set.
1096
+ *
1097
+ * @example
1098
+ * ```ts
1099
+ * import { override } from '@orkestrel/scaffold'
1100
+ *
1101
+ * override('README.md', '# router\n') // { path: 'README.md', content: '# router\n' }
1102
+ * ```
1103
+ */
1104
+ export declare function override(path: string, content: string): Override;
1105
+
1106
+ /**
1107
+ * Build the `Override` object shape.
1108
+ *
1109
+ * @returns A fresh `ContractShape` describing `{ path, content }`.
1110
+ */
1111
+ export declare function overrideShape(): ObjectShape<{
1112
+ path: StringShape;
1113
+ content: StringShape;
1114
+ }, false>;
1115
+
1116
+ /**
1117
+ * Compute the `package.json` artifact's `content`, applying the manifest and
1118
+ * exports combination rules over a blueprint's surfaces — grounded against the
1119
+ * live @orkestrel/middleware (core+server) and @orkestrel/router
1120
+ * (core+browser+server) exemplars.
1121
+ *
1122
+ * @param spec - The `Blueprint` to derive the manifest from.
1123
+ * @returns The `package.json` file content, newline-terminated.
1124
+ *
1125
+ * @example
1126
+ * ```ts
1127
+ * packageManifest(blueprint('router')) // '{\n\t"name": "@orkestrel/router",\n…}\n'
1128
+ * ```
1129
+ */
1130
+ export declare function packageManifest(spec: Blueprint): string;
1131
+
1132
+ /**
1133
+ * Right-pad a cell to a codepoint width, oxfmt-style.
1134
+ *
1135
+ * @param text - The cell text.
1136
+ * @param width - The target codepoint width.
1137
+ * @remarks
1138
+ * Measures via `Array.from` (codepoints, not UTF-16 code units) so a
1139
+ * surrogate-pair or wide codepoint counts once, matching oxfmt's own
1140
+ * width math. A cell already at or past `width` is returned unchanged.
1141
+ * @returns `text` padded with trailing spaces to `width` codepoints.
1142
+ *
1143
+ * @example
1144
+ * ```ts
1145
+ * import { padCell } from '@orkestrel/scaffold'
1146
+ *
1147
+ * padCell('ab', 5) // 'ab '
1148
+ * ```
1149
+ */
1150
+ export declare function padCell(text: string, width: number): string;
1151
+
1152
+ /**
1153
+ * Build the computed `SELF_SPECIFIERS` / `SPECIFIER_MODULES` / `exportsFor`
1154
+ * 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
1157
+ * both resolve a fence's specifier through a `SPECIFIER_MODULES` map rather
1158
+ * 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.
1161
+ *
1162
+ * @param spec - The `Blueprint` to derive the parity specifiers block from.
1163
+ * @returns The computed `parityTest` `{{specifiers}}` block content.
1164
+ *
1165
+ * @example
1166
+ * ```ts
1167
+ * paritySpecifiers(blueprint('router')).includes('SELF_SPECIFIERS') // true
1168
+ * ```
1169
+ */
1170
+ export declare function paritySpecifiers(spec: Blueprint): string;
1171
+
1172
+ /**
1173
+ * Parse a `Blueprint` from `unknown` (or a JSON string), else `undefined`.
1174
+ *
1175
+ * @remarks
1176
+ * The coercing counterpart of {@link isBlueprint}, compiled from the same
1177
+ * {@link blueprintShape} via `createContract` (AGENTS §14) — a guard-valid
1178
+ * value round-trips unchanged, an off-contract value returns `undefined`,
1179
+ * and this never throws, including on malformed JSON text.
1180
+ *
1181
+ * @param input - The value (or JSON string) to parse.
1182
+ * @returns A `Blueprint`, else `undefined`.
1183
+ */
1184
+ export declare const parseBlueprint: (input: unknown) => Blueprint | undefined;
1185
+
1186
+ /**
1187
+ * Parse a `Plan` from `unknown` (or a JSON string), else `undefined`.
1188
+ *
1189
+ * @remarks
1190
+ * The coercing counterpart of {@link isPlan}, compiled from the same
1191
+ * {@link planShape} via `createContract` (AGENTS §14) — a guard-valid value
1192
+ * round-trips unchanged, an off-contract value returns `undefined`, and this
1193
+ * never throws, including on malformed JSON text.
1194
+ *
1195
+ * @param input - The value (or JSON string) to parse.
1196
+ * @returns A `Plan`, else `undefined`.
1197
+ */
1198
+ export declare const parsePlan: (input: unknown) => Plan | undefined;
1199
+
1200
+ /**
1201
+ * Parse a `SyncReport` from `unknown` (or a JSON string), else `undefined`.
1202
+ *
1203
+ * @remarks
1204
+ * The coercing counterpart of {@link isSyncReport}, compiled from the same
1205
+ * {@link syncReportShape} via `createContract` (AGENTS §14) — a guard-valid
1206
+ * value round-trips unchanged, an off-contract value returns `undefined`,
1207
+ * and this never throws, including on malformed JSON text.
1208
+ *
1209
+ * @param input - The value (or JSON string) to parse.
1210
+ * @returns A `SyncReport`, else `undefined`.
1211
+ */
1212
+ export declare const parseSyncReport: (input: unknown) => SyncReport | undefined;
1213
+
1214
+ /**
1215
+ * Derive the PascalCase entity name from a lowercase-hyphen package name.
1216
+ *
1217
+ * @param name - A lowercase-hyphen package name.
1218
+ * @returns The PascalCase entity name — hyphens are word breaks.
1219
+ *
1220
+ * @example
1221
+ * ```ts
1222
+ * import { pascalCase } from '@orkestrel/scaffold'
1223
+ *
1224
+ * pascalCase('my-router') // 'MyRouter'
1225
+ * ```
1226
+ */
1227
+ export declare function pascalCase(name: string): string;
1228
+
1229
+ /**
1230
+ * Return a fresh `Plan` with `trace` and `hash` filled.
1231
+ *
1232
+ * @param plan - The plan to pin.
1233
+ * @remarks
1234
+ * `hash` is a canonical `computeHash` digest of the plan's
1235
+ * blueprint/groups/artifacts, serialized through `stableStringify` —
1236
+ * deterministic, no clocks or randomness. `trace` is a one-line derivation
1237
+ * summary built from the plan's own `PlanSummary`.
1238
+ * @returns The plan with `trace` and `hash` filled.
1239
+ *
1240
+ * @example
1241
+ * ```ts
1242
+ * import { pinPlan } from '@orkestrel/scaffold'
1243
+ *
1244
+ * pinPlan(plan).trace // 'router · core+browser · groups:7 · artifacts:21'
1245
+ * ```
1246
+ */
1247
+ export declare function pinPlan(plan: Plan): Plan;
1248
+
1249
+ /** The compiled, ordered artifact list plus the selection it covers; `trace` / `hash` filled by the pin. */
1250
+ export declare interface Plan {
1251
+ readonly blueprint: Blueprint;
1252
+ readonly groups: readonly Group[];
1253
+ readonly artifacts: readonly Artifact[];
1254
+ readonly trace?: string;
1255
+ readonly hash?: string;
1256
+ }
1257
+
1258
+ /**
1259
+ * The self-owning, versioned/hashed plan registry (AGENTS §9).
1260
+ *
1261
+ * @remarks
1262
+ * `add` re-pins the plan and mints the record's `id` from its own content
1263
+ * `hash` — deterministic, no randomness. Re-adding a plan whose content is
1264
+ * unchanged resolves to the SAME id and returns the existing record
1265
+ * 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', …)`.
1270
+ *
1271
+ * @example
1272
+ * ```ts
1273
+ * import { blueprint, blueprintToPlan, PlanManager } from '@src/core'
1274
+ *
1275
+ * const plans = new PlanManager()
1276
+ * const record = plans.add(blueprintToPlan(blueprint('budget', { surfaces: ['core'] })))
1277
+ * record.id === record.hash // true — id minted from content
1278
+ * plans.destroy()
1279
+ * ```
1280
+ */
1281
+ export declare class PlanManager implements PlanManagerInterface {
1282
+ #private;
1283
+ constructor(options?: PlanManagerOptions);
1284
+ get emitter(): EmitterInterface<PlanManagerEventMap>;
1285
+ get size(): number;
1286
+ /**
1287
+ * Whether a plan with the given id is registered.
1288
+ *
1289
+ * @param id - The plan record id.
1290
+ * @returns `true` when `id` is registered.
1291
+ */
1292
+ has(id: string): boolean;
1293
+ /**
1294
+ * Look up one registered plan record by id (AGENTS §9.1 singular accessor).
1295
+ *
1296
+ * @param id - The plan record id.
1297
+ * @returns The `PlanRecord`, or `undefined` when unregistered.
1298
+ */
1299
+ plan(id: string): PlanRecord | undefined;
1300
+ /**
1301
+ * List every registered plan record (AGENTS §9.1 plural accessor).
1302
+ *
1303
+ * @returns A snapshot array of every registered `PlanRecord`.
1304
+ */
1305
+ plans(): readonly PlanRecord[];
1306
+ /**
1307
+ * Register (or re-register) one plan, mints the record's id from its
1308
+ * content hash.
1309
+ *
1310
+ * @param plan - The `Plan` to register.
1311
+ * @returns The registered `PlanRecord`.
1312
+ *
1313
+ * @example
1314
+ * ```ts
1315
+ * const record = plans.add(blueprintToPlan(blueprint('budget', { surfaces: ['core'] })))
1316
+ * record.version // 1
1317
+ * ```
1318
+ */
1319
+ add(plan: Plan): PlanRecord;
1320
+ /**
1321
+ * Remove one, several, or every registered plan (AGENTS §9.2 batch
1322
+ * overloads) — array overload declared first so a list resolves to the
1323
+ * batch form.
1324
+ *
1325
+ * @remarks
1326
+ * `remove()` removes every registered plan, emitting `remove` once per id.
1327
+ * `remove(id)` removes one plan, emitting `remove` and returning `true`
1328
+ * when it existed, `false` otherwise. `remove(ids)` is ALL-OR-NOTHING: if
1329
+ * any listed id is unregistered, the collection is left untouched and
1330
+ * `false` is returned.
1331
+ *
1332
+ * @param target - Omit to remove all, a single id, or a list of ids.
1333
+ * @returns `boolean` for the single-id / list-of-ids forms; `void` for the remove-all form.
1334
+ */
1335
+ remove(ids: readonly string[]): boolean;
1336
+ remove(id: string): boolean;
1337
+ remove(): void;
1338
+ /** Idempotent teardown — clears the collection, emits `destroy`, then destroys the emitter LAST. */
1339
+ destroy(): void;
1340
+ }
1341
+
1342
+ /** `PlanManager`'s push observation surface (AGENTS §13). */
1343
+ export declare type PlanManagerEventMap = {
1344
+ readonly add: readonly [id: string];
1345
+ readonly remove: readonly [id: string];
1346
+ readonly destroy: readonly [];
1347
+ };
1348
+
1349
+ /** The plan registry contract (AGENTS §9). */
1350
+ export declare interface PlanManagerInterface {
1351
+ readonly emitter: EmitterInterface<PlanManagerEventMap>;
1352
+ readonly size: number;
1353
+ has(id: string): boolean;
1354
+ plan(id: string): PlanRecord | undefined;
1355
+ plans(): readonly PlanRecord[];
1356
+ add(plan: Plan): PlanRecord;
1357
+ remove(ids: readonly string[]): boolean;
1358
+ remove(id: string): boolean;
1359
+ remove(): void;
1360
+ destroy(): void;
1361
+ }
1362
+
1363
+ /** Options for `createPlanManager` / the `PlanManager` constructor. */
1364
+ export declare interface PlanManagerOptions {
1365
+ readonly plans?: readonly Plan[];
1366
+ readonly on?: EmitterHooks<PlanManagerEventMap>;
1367
+ readonly error?: EmitterErrorHandler;
1368
+ }
1369
+
1370
+ /** A versioned, content-hashed `Plan` inside a `PlanManager`. */
1371
+ export declare interface PlanRecord {
1372
+ readonly id: string;
1373
+ readonly plan: Plan;
1374
+ readonly version: number;
1375
+ readonly hash: string;
1376
+ }
1377
+
1378
+ /**
1379
+ * Build the whole `Plan` object shape.
1380
+ *
1381
+ * @remarks
1382
+ * Composes {@link blueprintShape} and {@link artifactShape}; `trace` and
1383
+ * `hash` are optional (filled by the pin).
1384
+ *
1385
+ * @returns A fresh `ContractShape` describing the compiled, ordered plan.
1386
+ */
1387
+ export declare function planShape(): ObjectShape<{
1388
+ blueprint: ObjectShape<{
1389
+ name: StringShape;
1390
+ description: OptionalShape<StringShape>;
1391
+ keywords: ArrayShape<StringShape>;
1392
+ surfaces: ArrayShape<LiteralShape<readonly ["core", "browser", "server"]>>;
1393
+ dependencies: ArrayShape<ObjectShape<{
1394
+ name: StringShape;
1395
+ range: StringShape;
1396
+ optional: OptionalShape<BooleanShape>;
1397
+ }, false>>;
1398
+ peers: ArrayShape<ObjectShape<{
1399
+ name: StringShape;
1400
+ range: StringShape;
1401
+ optional: OptionalShape<BooleanShape>;
1402
+ }, false>>;
1403
+ extras: ArrayShape<ObjectShape<{
1404
+ name: StringShape;
1405
+ range: StringShape;
1406
+ optional: OptionalShape<BooleanShape>;
1407
+ }, false>>;
1408
+ version: StringShape;
1409
+ engines: StringShape;
1410
+ overrides: ArrayShape<ObjectShape<{
1411
+ path: StringShape;
1412
+ content: StringShape;
1413
+ }, false>>;
1414
+ }, false>;
1415
+ groups: ArrayShape<LiteralShape<readonly ["manifest", "configs", "source", "tests", "guides", "docs", "orchestration"]>>;
1416
+ artifacts: ArrayShape<ObjectShape<{
1417
+ 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>;
1422
+ source: OptionalShape<StringShape>;
1423
+ }, false>>;
1424
+ trace: OptionalShape<StringShape>;
1425
+ hash: OptionalShape<StringShape>;
1426
+ }, false>;
1427
+
1428
+ /** The dry-run tally. */
1429
+ export declare interface PlanSummary {
1430
+ readonly name: string;
1431
+ readonly surfaces: readonly Surface[];
1432
+ readonly groups: readonly Group[];
1433
+ readonly artifacts: number;
1434
+ readonly host: number;
1435
+ readonly template: number;
1436
+ readonly computed: number;
1437
+ }
1438
+
1439
+ /**
1440
+ * Project a `Plan` into a copy-ready markdown review document.
1441
+ *
1442
+ * @param plan - The plan to review.
1443
+ * @returns The artifact table by group, the members table, and the summary — the diff-first dry run.
1444
+ *
1445
+ * @example
1446
+ * ```ts
1447
+ * import { planToReview } from '@orkestrel/scaffold'
1448
+ *
1449
+ * planToReview(plan) // '# Scaffolding router\n## Artifacts\n| Path | Group | Origin |\n…'
1450
+ * ```
1451
+ */
1452
+ export declare function planToReview(plan: Plan): string;
1453
+
1454
+ /**
1455
+ * Project a `Plan` into a `PlanSummary`.
1456
+ *
1457
+ * @param plan - The plan to summarize.
1458
+ * @returns The artifact tally by `origin`, the surfaces, and the covered groups.
1459
+ *
1460
+ * @example
1461
+ * ```ts
1462
+ * import { planToSummary } from '@orkestrel/scaffold'
1463
+ *
1464
+ * planToSummary(plan) // { name: 'router', artifacts: 21, host: 12, template: 6, computed: 3, … }
1465
+ * ```
1466
+ */
1467
+ export declare function planToSummary(plan: Plan): PlanSummary;
1468
+
1469
+ /**
1470
+ * One validation issue.
1471
+ *
1472
+ * @remarks
1473
+ * `blocking: true` fails the gate closed, `false` is an advisory that rides a
1474
+ * complete result.
1475
+ */
1476
+ export declare interface Question {
1477
+ readonly field: string;
1478
+ readonly text: string;
1479
+ readonly blocking: boolean;
1480
+ readonly candidates?: readonly string[];
1481
+ }
1482
+
1483
+ /**
1484
+ * Compare a declared range to the registry latest.
1485
+ *
1486
+ * @param range - The declared semver range.
1487
+ * @param latest - The registry's latest published version.
1488
+ * @remarks
1489
+ * The `0.0.x` exact-pin law: `'current'` iff `range`'s `^0.0.N` exact pin
1490
+ * equals `latest`, else `'behind'`. The `'missing'` / `'failed'` verdicts
1491
+ * come from the fetch layer, never this pure comparison.
1492
+ * @returns `'current'` or `'behind'`.
1493
+ *
1494
+ * @example
1495
+ * ```ts
1496
+ * import { rangeToFreshness } from '@orkestrel/scaffold'
1497
+ *
1498
+ * rangeToFreshness('^0.0.5', '0.0.5') // 'current' — pinned to latest
1499
+ * rangeToFreshness('^0.0.5', '0.0.7') // 'behind' — a newer patch is published
1500
+ * ```
1501
+ */
1502
+ export declare function rangeToFreshness(range: string, latest: string): Freshness;
1503
+
1504
+ /**
1505
+ * The root `tsconfig.json` — one `@src/<surface>` path alias per declared
1506
+ * surface, in declared order.
1507
+ *
1508
+ * @param surfaces - The declared `Surface[]`.
1509
+ * @returns The root `tsconfig.json` file content, newline-terminated.
1510
+ *
1511
+ * @example
1512
+ * ```ts
1513
+ * rootTsconfig(['core']) // '{\n\t"compilerOptions": {…}\n}\n'
1514
+ * ```
1515
+ */
1516
+ export declare function rootTsconfig(surfaces: readonly Surface[]): string;
1517
+
1518
+ /**
1519
+ * The root `vite.config.ts` — three grounded shapes, chosen by a blueprint's
1520
+ * `surfaces`:
1521
+ * 1. `core`-only — `srcCore` + `guides`, no Playwright at all (the live
1522
+ * timeout exemplar: no browser project exists anywhere in the file).
1523
+ * 2. Multi-surface (2+ surfaces, always including `core` per the live
1524
+ * middleware/router exemplars) — `srcCore` is the shared base;
1525
+ * `srcBrowser` / `srcServer` extend it and externalize `@src/core` to
1526
+ * 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
1530
+ * dead `@src/core` externalize/remap either — there is no sibling
1531
+ * core build), per the live sqlite (server-only) / indexeddb
1532
+ * (browser-only) exemplars. Playwright ships only when the sole
1533
+ * surface is `browser` (it must run its own tests in a real browser).
1534
+ *
1535
+ * @param surfaces - The declared `Surface[]`.
1536
+ * @returns The root `vite.config.ts` file content, newline-terminated.
1537
+ *
1538
+ * @example
1539
+ * ```ts
1540
+ * rootViteConfig(['core']).includes('srcCore') // true
1541
+ * ```
1542
+ */
1543
+ export declare function rootViteConfig(surfaces: readonly Surface[]): string;
1544
+
1545
+ /** The devDependency range generated packages pin `@orkestrel/scaffold` at. */
1546
+ export declare const SCAFFOLD_RANGE = "^0.0.1";
1547
+
1548
+ /**
1549
+ * Carries a `ScaffoldErrorCode` + optional `context` (AGENTS §12).
1550
+ *
1551
+ * @remarks
1552
+ * Throws are reserved for caller misuse: `createBlueprint` on off-contract
1553
+ * data throws `INVALID`, any method after `destroy()` throws `DESTROYED`, and
1554
+ * on the server surface a non-vacant target throws `TARGET` while a failed
1555
+ * write throws `WRITE`. A failing gate is NOT an error — it fails closed into
1556
+ * an incomplete `Scaffolding` whose `failures` carry a `BLOCKED` marker.
1557
+ *
1558
+ * @example
1559
+ * ```ts
1560
+ * import { ScaffoldError, isScaffoldError } from '@orkestrel/scaffold'
1561
+ *
1562
+ * try {
1563
+ * throw new ScaffoldError('INVALID', 'Blueprint failed the exact-record contract')
1564
+ * } catch (error) {
1565
+ * if (isScaffoldError(error)) error.code // 'INVALID'
1566
+ * }
1567
+ * ```
1568
+ */
1569
+ export declare class ScaffoldError extends Error {
1570
+ readonly code: ScaffoldErrorCode;
1571
+ readonly context?: unknown;
1572
+ constructor(code: ScaffoldErrorCode, message: string, context?: unknown);
1573
+ }
1574
+
1575
+ /** Coded `ScaffoldError` reasons. */
1576
+ export declare type ScaffoldErrorCode = 'INVALID' | 'BLOCKED' | 'DESTROYED' | 'TARGET' | 'WRITE' | 'FETCH';
1577
+
1578
+ /** The full, replayable outcome of one `compile()` call. */
1579
+ export declare interface Scaffolding {
1580
+ readonly blueprint: Blueprint;
1581
+ readonly plan?: Plan;
1582
+ readonly questions: readonly Question[];
1583
+ readonly stages: readonly CompileRecord[];
1584
+ readonly failures: readonly CompileFailure[];
1585
+ readonly complete: boolean;
1586
+ readonly digest: string;
1587
+ }
1588
+
1589
+ /**
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.
1594
+ *
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.
1597
+ *
1598
+ * @example
1599
+ * ```ts
1600
+ * singleSurfaceViteConfig('server').includes('srcServer') // true
1601
+ * ```
1602
+ */
1603
+ export declare function singleSurfaceViteConfig(surface: 'browser' | 'server'): string;
1604
+
1605
+ /**
1606
+ * 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
1609
+ * `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.
1612
+ *
1613
+ * @param spec - The `Blueprint` to derive source stubs from.
1614
+ * @param pascal - The package's PascalCase entity name.
1615
+ * @returns The `source` group's `Artifact[]`.
1616
+ *
1617
+ * @example
1618
+ * ```ts
1619
+ * sourceArtifacts(blueprint('router'), 'Router').length // 4
1620
+ * ```
1621
+ */
1622
+ export declare function sourceArtifacts(spec: Blueprint, pascal: string): readonly Artifact[];
1623
+
1624
+ /**
1625
+ * Split one rendered GFM table row into its trimmed cell strings.
1626
+ *
1627
+ * @param line - A single rendered table line (header, delimiter, or body row).
1628
+ * @remarks
1629
+ * Splits on an UNESCAPED `|` (a `\|` is a literal pipe inside a cell, not a
1630
+ * column boundary), then drops the leading/trailing empty segments the
1631
+ * boundary pipes produce and trims each remaining cell.
1632
+ * @returns The row's cell strings, in column order.
1633
+ *
1634
+ * @example
1635
+ * ```ts
1636
+ * import { splitTableRow } from '@orkestrel/scaffold'
1637
+ *
1638
+ * splitTableRow('| a | b |') // ['a', 'b']
1639
+ * ```
1640
+ */
1641
+ export declare function splitTableRow(line: string): readonly string[];
1642
+
1643
+ /**
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`
1667
+ * files, Vitest project label, `exports` subpath, and build formats — the
1668
+ * per-surface layer `blueprintToPlan` reads BENEATH the manifest/exports
1669
+ * combination rules it applies on top.
1670
+ */
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"];
1694
+
1695
+ /**
1696
+ * `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
1698
+ * middleware/router exemplars.
1699
+ *
1700
+ * @param surface - The non-`core` surface to derive the `tsconfig` for.
1701
+ * @returns The surface `tsconfig` file content, newline-terminated.
1702
+ *
1703
+ * @example
1704
+ * ```ts
1705
+ * surfaceTsconfig('server').includes('"rootDir": "../../src"') // true
1706
+ * ```
1707
+ */
1708
+ export declare function surfaceTsconfig(surface: 'browser' | 'server'): string;
1709
+
1710
+ /**
1711
+ * Classify a blueprint's surfaces into the manifest/exports variant class.
1712
+ *
1713
+ * @param surfaces - The declared `Surface[]`.
1714
+ * @returns The sole declared `Surface`, or `'multi'` when two or more are declared.
1715
+ *
1716
+ * @example
1717
+ * ```ts
1718
+ * surfaceVariant(['core']) // 'core'
1719
+ * surfaceVariant(['core', 'server']) // 'multi'
1720
+ * ```
1721
+ */
1722
+ export declare function surfaceVariant(surfaces: readonly Surface[]): Surface | 'multi';
1723
+
1724
+ /**
1725
+ * `configs/src/vite.<browser|server>.config.ts` — a thin `dts`-only wrapper;
1726
+ * `build.lib` / externals live in the root `srcBrowser` / `srcServer` export
1727
+ * instead (per the live exemplars).
1728
+ *
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.
1731
+ *
1732
+ * @example
1733
+ * ```ts
1734
+ * surfaceViteConfig('browser').includes('srcBrowser') // true
1735
+ * ```
1736
+ */
1737
+ export declare function surfaceViteConfig(surface: 'browser' | 'server'): string;
1738
+
1739
+ /**
1740
+ * The whole outcome of a `Sync.pull`.
1741
+ *
1742
+ * @remarks
1743
+ * `clean` is `true` iff no drift AND no failures; `failed` is the count of
1744
+ * guide/version fetches that came back `missing` or `failed`.
1745
+ */
1746
+ export declare interface SyncReport {
1747
+ readonly target: string;
1748
+ readonly guides: readonly GuideSync[];
1749
+ readonly versions: readonly VersionSync[];
1750
+ readonly clean: boolean;
1751
+ readonly failed: number;
1752
+ }
1753
+
1754
+ /**
1755
+ * Build the `SyncReport` object shape.
1756
+ *
1757
+ * @remarks
1758
+ * `guides` / `versions` are array sub-shapes, each with a
1759
+ * `literalShape(FRESHNESS)` `freshness` field; `isSyncReport` /
1760
+ * `parseSyncReport` compile from it.
1761
+ *
1762
+ * @returns A fresh `ContractShape` describing the whole sync outcome.
1763
+ */
1764
+ export declare function syncReportShape(): ObjectShape<{
1765
+ target: StringShape;
1766
+ guides: ArrayShape<ObjectShape<{
1767
+ name: StringShape;
1768
+ path: StringShape;
1769
+ content: StringShape;
1770
+ freshness: LiteralShape<readonly ["current", "behind", "missing", "failed"]>;
1771
+ note: OptionalShape<StringShape>;
1772
+ }, boolean | ContractShape>>;
1773
+ versions: ArrayShape<ObjectShape<{
1774
+ name: StringShape;
1775
+ range: StringShape;
1776
+ latest: StringShape;
1777
+ freshness: LiteralShape<readonly ["current", "behind", "missing", "failed"]>;
1778
+ note: OptionalShape<StringShape>;
1779
+ }, boolean | ContractShape>>;
1780
+ clean: BooleanShape;
1781
+ failed: NumberShape;
1782
+ }, false>;
1783
+
1784
+ /**
1785
+ * Project a `SyncReport` into a markdown freshness report.
1786
+ *
1787
+ * @param report - The sync report to render.
1788
+ * @returns Guides and versions each in their own table, via `alignTable` — the sibling of `auditToReview`.
1789
+ *
1790
+ * @example
1791
+ * ```ts
1792
+ * import { syncToReview } from '@orkestrel/scaffold'
1793
+ *
1794
+ * syncToReview(report) // '# Sync — 2 behind\n## Guides\n| Name | Freshness |\n…'
1795
+ * ```
1796
+ */
1797
+ export declare function syncToReview(report: SyncReport): string;
1798
+
1799
+ /**
1800
+ * The shipped, versioned `TemplateDefinition` data behind every
1801
+ * `template`-origin artifact `blueprintToPlan` renders.
1802
+ *
1803
+ * @remarks
1804
+ * The generated-minimal stub prose/source, expressed as `{{name}}` /
1805
+ * `{{pascal}}` `{{token}}` placeholders for `@orkestrel/template`'s pure
1806
+ * `fillTemplate` LEAF. Only genuinely templated PROSE / source artifacts live
1807
+ * here — the token-collision boundary (AGENTS §14, this guide's Contract
1808
+ * invariant 3) keeps every STRUCTURAL file (`package.json`, the tsconfigs,
1809
+ * the vite configs) `computed` inside `blueprintToPlan` instead, so a literal
1810
+ * `{{…}}` in a config can never be mistaken for a placeholder. A convention
1811
+ * change here is a version bump of this package, never a hand-edit of a
1812
+ * scaffolded repo's copy.
1813
+ */
1814
+ export declare const TEMPLATES: Readonly<Record<string, TemplateDefinition>>;
1815
+
1816
+ /**
1817
+ * Draft the `tests` group's `template` artifacts — the shared recorder
1818
+ * setup, one environment-specific setup file per non-`core` surface
1819
+ * (`setupServer.ts` / `setupBrowser.ts`, grounded against the live
1820
+ * exemplars' setup-file naming), the generated-minimal entity / factory test
1821
+ * stubs PER declared surface, and the surface-aware guides-parity drop-in.
1822
+ *
1823
+ * @param spec - The `Blueprint` to derive test stubs from.
1824
+ * @param pascal - The package's PascalCase entity name.
1825
+ * @returns The `tests` group's `Artifact[]`.
1826
+ *
1827
+ * @example
1828
+ * ```ts
1829
+ * testArtifacts(blueprint('router'), 'Router').length // 3
1830
+ * ```
1831
+ */
1832
+ export declare function testArtifacts(spec: Blueprint, pascal: string): readonly Artifact[];
1833
+
1834
+ /**
1835
+ * The semantic pass over a blueprint.
1836
+ *
1837
+ * @param spec - The blueprint to validate.
1838
+ * @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` /
1849
+ * `extras` (non-empty name/range, no duplicate names within an array):
1850
+ * `dependencies` and `peers` names are shaped `DEPENDENCY_NAME_PATTERN`
1851
+ * (closed to `@orkestrel/*`) — a NAME-shaped law at the gate that closes the
1852
+ * traversal vector a hand-built `../`-laced dependency name would open
1853
+ * through `Compiler.#pointerArtifacts`'s path derivation; `extras` names are
1854
+ * shaped `EXTRA_NAME_PATTERN` instead — broader (any valid npm package name),
1855
+ * safe because `extras` never feeds a path, only `devDependencies` content. A
1856
+ * name appearing in both `dependencies` and `peers` is a blocking question
1857
+ * (npm forbids sensibly declaring the same package both ways), and an
1858
+ * `extras` name may overlap neither `dependencies` nor `peers`.
1859
+ * @returns A `Validation` — never throws.
1860
+ *
1861
+ * @example
1862
+ * ```ts
1863
+ * import { validateBlueprint } from '@orkestrel/scaffold'
1864
+ *
1865
+ * validateBlueprint(blueprint('router')) // { valid: true, questions: [], warnings: [] }
1866
+ * ```
1867
+ */
1868
+ export declare function validateBlueprint(spec: Blueprint): Validation;
1869
+
1870
+ /**
1871
+ * Validate one dependency-shaped array under the name/range/duplicate rules.
1872
+ *
1873
+ * @param field - The `Question.field` to attribute a violation to (`'dependencies'` / `'peers'` / `'extras'`).
1874
+ * @param items - The `Dependency[]` to check.
1875
+ * @remarks
1876
+ * Pure — takes no closed-over `questions` array to mutate; the caller
1877
+ * concatenates the returned `questions` and inspects the returned `seen` set
1878
+ * to apply the cross-array (`dependencies` vs `peers` vs `extras`) overlap
1879
+ * rules `validateBlueprint` layers on top. `field === 'extras'` validates
1880
+ * names against `EXTRA_NAME_PATTERN` (broader — any valid npm package name);
1881
+ * `'dependencies'` and `'peers'` keep `DEPENDENCY_NAME_PATTERN` (closed to
1882
+ * `@orkestrel/*`) — the path-derived arrays stay orkestrel-closed, since only
1883
+ * `dependencies`/`peers` names ever reach `Compiler.#pointerArtifacts`' path
1884
+ * derivation; `extras` names are manifest-content only.
1885
+ * @returns The violations found and the set of names seen, in encounter order.
1886
+ *
1887
+ * @example
1888
+ * ```ts
1889
+ * import { validateDependencyArray } from '@orkestrel/scaffold'
1890
+ *
1891
+ * validateDependencyArray('dependencies', [{ name: '', range: '^1' }])
1892
+ * // { questions: [{ field: 'dependencies', text: 'A dependency name must not be empty', … }], seen: Set(0) {} }
1893
+ * ```
1894
+ */
1895
+ export declare function validateDependencyArray(field: string, items: readonly Dependency[]): {
1896
+ readonly questions: readonly Question[];
1897
+ readonly seen: ReadonlySet<string>;
1898
+ };
1899
+
1900
+ /** The semantic pass over a blueprint; returns, never throws. */
1901
+ export declare interface Validation {
1902
+ readonly valid: boolean;
1903
+ readonly questions: readonly Question[];
1904
+ readonly warnings: readonly string[];
1905
+ }
1906
+
1907
+ /**
1908
+ * One dependency's declared `range` against the registry `latest`, plus its
1909
+ * `freshness` verdict.
1910
+ *
1911
+ * @remarks
1912
+ * `note` carries the failure/anomaly CAUSE — see {@link GuideSync.note}.
1913
+ */
1914
+ export declare interface VersionSync {
1915
+ readonly name: string;
1916
+ readonly range: string;
1917
+ readonly latest: string;
1918
+ readonly freshness: Freshness;
1919
+ readonly note?: string;
1920
+ }
1921
+
1922
+ /**
1923
+ * 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
1928
+ * `core`-only.
1929
+ *
1930
+ * @param needsPlaywright - Whether this shape ships a browser test project (and so needs Playwright).
1931
+ * @returns The rendered header block, newline-terminated.
1932
+ *
1933
+ * @example
1934
+ * ```ts
1935
+ * viteHeader(false).includes('@vitest/browser-playwright') // false
1936
+ * viteHeader(true).includes('@vitest/browser-playwright') // true
1937
+ * ```
1938
+ */
1939
+ export declare function viteHeader(needsPlaywright: boolean): string;
1940
+
1941
+ export { }