@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.
- package/LICENSE +21 -0
- package/README.md +114 -0
- package/dist/bin/scaffold.js +1539 -0
- package/dist/bin/scaffold.js.map +1 -0
- package/dist/host/AGENTS.md +939 -0
- package/dist/host/CLAUDE.md +495 -0
- package/dist/host/LICENSE +21 -0
- package/dist/host/claude/agents/builder.md +48 -0
- package/dist/host/claude/agents/checker.md +37 -0
- package/dist/host/claude/agents/composer.md +64 -0
- package/dist/host/claude/agents/grok.md +50 -0
- package/dist/host/claude/agents/orkestrel.md +236 -0
- package/dist/host/claude/agents/planner.md +44 -0
- package/dist/host/claude/agents/researcher.md +38 -0
- package/dist/host/claude/agents/reviewer.md +47 -0
- package/dist/host/claude/agents/scout.md +35 -0
- package/dist/host/claude/agents/verifier.md +34 -0
- package/dist/host/claude/settings.json +26 -0
- package/dist/host/dotfiles/editorconfig +17 -0
- package/dist/host/dotfiles/gitattributes +3 -0
- package/dist/host/dotfiles/gitignore +40 -0
- package/dist/host/dotfiles/oxfmtrc.json +18 -0
- package/dist/host/dotfiles/oxlintignore +20 -0
- package/dist/host/dotfiles/oxlintrc.json +58 -0
- package/dist/host/dotfiles/prettierignore +5 -0
- package/dist/host/github/workflows/ci.yml +64 -0
- package/dist/host/guides/src/guide.md +312 -0
- package/dist/host/guides/src/scaffold.md +2152 -0
- package/dist/host/manifest.json +137 -0
- package/dist/host/scripts/cursor.sh +74 -0
- package/dist/host/scripts/deps.sh +38 -0
- package/dist/host/scripts/ollama.sh +163 -0
- package/dist/src/core/index.cjs +3728 -0
- package/dist/src/core/index.cjs.map +1 -0
- package/dist/src/core/index.d.cts +1941 -0
- package/dist/src/core/index.d.ts +1941 -0
- package/dist/src/core/index.js +3636 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/server/index.cjs +1595 -0
- package/dist/src/server/index.cjs.map +1 -0
- package/dist/src/server/index.d.cts +779 -0
- package/dist/src/server/index.d.ts +779 -0
- package/dist/src/server/index.js +1572 -0
- package/dist/src/server/index.js.map +1 -0
- 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 { }
|