@orkestrel/scaffold 0.0.6 → 0.0.8
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/dist/bin/scaffold.js +90 -41
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/CLAUDE.md +53 -27
- package/dist/host/guides/src/scaffold.md +303 -154
- package/dist/host/tests/setupPolicy.ts +1 -0
- package/dist/src/core/index.cjs +639 -322
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +189 -31
- package/dist/src/core/index.d.ts +189 -31
- package/dist/src/core/index.js +629 -323
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +45 -14
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +16 -6
- package/dist/src/server/index.d.ts +16 -6
- package/dist/src/server/index.js +46 -16
- package/dist/src/server/index.js.map +1 -1
- package/package.json +11 -9
|
@@ -127,49 +127,51 @@ plan.artifacts.some((artifact) => artifact.path === 'app/server/main.ts') // tru
|
|
|
127
127
|
|
|
128
128
|
From [`types.ts`](../../src/core/types.ts).
|
|
129
129
|
|
|
130
|
-
| Name
|
|
131
|
-
|
|
|
132
|
-
| `Environment`
|
|
133
|
-
| `BuildFormat`
|
|
134
|
-
| `SrcDefinition`
|
|
135
|
-
| `AppDefinition`
|
|
136
|
-
| `ViteMachinery`
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
130
|
+
| Name | Kind |
|
|
131
|
+
| ------------------------- | --------- |
|
|
132
|
+
| `Environment` | type |
|
|
133
|
+
| `BuildFormat` | type |
|
|
134
|
+
| `SrcDefinition` | interface |
|
|
135
|
+
| `AppDefinition` | interface |
|
|
136
|
+
| `ViteMachinery` | interface |
|
|
137
|
+
| `ViteAxes` | interface |
|
|
138
|
+
| `ViteProjectRegistration` | interface |
|
|
139
|
+
| `Origin` | type |
|
|
140
|
+
| `Group` | type |
|
|
141
|
+
| `Category` | type |
|
|
142
|
+
| `CatalogEntry` | interface |
|
|
143
|
+
| `Drift` | type |
|
|
144
|
+
| `Freshness` | type |
|
|
145
|
+
| `CompileStage` | type |
|
|
146
|
+
| `ScaffoldErrorCode` | type |
|
|
147
|
+
| `Dependency` | interface |
|
|
148
|
+
| `Override` | interface |
|
|
149
|
+
| `Blueprint` | interface |
|
|
150
|
+
| `Member` | interface |
|
|
151
|
+
| `ArtifactBase` | interface |
|
|
152
|
+
| `HostArtifact` | interface |
|
|
153
|
+
| `ContentArtifact` | interface |
|
|
154
|
+
| `Artifact` | type |
|
|
155
|
+
| `Snapshot` | type |
|
|
156
|
+
| `Plan` | interface |
|
|
157
|
+
| `Finding` | interface |
|
|
158
|
+
| `Audit` | interface |
|
|
159
|
+
| `Question` | interface |
|
|
160
|
+
| `Validation` | interface |
|
|
161
|
+
| `GuideSync` | interface |
|
|
162
|
+
| `VersionSync` | interface |
|
|
163
|
+
| `SyncReport` | interface |
|
|
164
|
+
| `PlanSummary` | interface |
|
|
165
|
+
| `CompileRecord` | interface |
|
|
166
|
+
| `CompileFailure` | interface |
|
|
167
|
+
| `Scaffolding` | interface |
|
|
168
|
+
| `PlanRecord` | interface |
|
|
169
|
+
| `CompilerEventMap` | type |
|
|
170
|
+
| `CompilerOptions` | interface |
|
|
171
|
+
| `CompilerInterface` | interface |
|
|
172
|
+
| `PlanManagerEventMap` | type |
|
|
173
|
+
| `PlanManagerOptions` | interface |
|
|
174
|
+
| `PlanManagerInterface` | interface |
|
|
173
175
|
|
|
174
176
|
The closed vocabularies are small and total. `Environment` is `'core' | 'browser' | 'server'`.
|
|
175
177
|
`BuildFormat` is `'es' | 'cjs'`. `Origin` is `'host' | 'template' | 'computed'`. `Group` is
|
|
@@ -190,6 +192,13 @@ single-file-component, HTML, and development-server machinery an application bro
|
|
|
190
192
|
needs, and `output` for build-output containment. It never selects a boundary guarantee — those ship
|
|
191
193
|
in every shape, as the compilers section sets out.
|
|
192
194
|
|
|
195
|
+
`ViteAxes` is the optional structural-project slice shared by every root Vite compiler:
|
|
196
|
+
`bin`, `integration`, and `service` each select their matching standalone project when `true`.
|
|
197
|
+
|
|
198
|
+
`ViteProjectRegistration` carries one generated project factory identifier and its optional browser
|
|
199
|
+
label. Root configuration renderers preserve that browser ownership as data through registration
|
|
200
|
+
instead of inferring it from a project identifier.
|
|
201
|
+
|
|
193
202
|
`Blueprint` is the closed input spec:
|
|
194
203
|
|
|
195
204
|
```ts
|
|
@@ -205,19 +214,44 @@ interface Blueprint {
|
|
|
205
214
|
readonly version: string
|
|
206
215
|
readonly engines: string
|
|
207
216
|
readonly overrides: readonly Override[]
|
|
208
|
-
readonly
|
|
217
|
+
readonly bin: boolean
|
|
218
|
+
readonly integration: boolean
|
|
219
|
+
readonly service: boolean
|
|
209
220
|
}
|
|
210
221
|
```
|
|
211
222
|
|
|
212
|
-
`src` selects published library environments under `src`; `app` selects private runtime
|
|
213
|
-
`app`. The two axes are independent, so library-only, application-only, and
|
|
214
|
-
all first class. `dependencies` and `peers` are runtime `@orkestrel/*`
|
|
215
|
-
`optional` also gets a `peerDependenciesMeta` entry. `extras` are
|
|
216
|
-
dependencies merged over the generated baseline, and may carry any
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
`
|
|
223
|
+
`src` selects published library environments under `src`; `app` selects private runtime
|
|
224
|
+
environments under `app`. The two axes are independent, so library-only, application-only, and
|
|
225
|
+
mixed workspaces are all first class. `dependencies` and `peers` are runtime `@orkestrel/*`
|
|
226
|
+
packages — a peer flagged `optional` also gets a `peerDependenciesMeta` entry. `extras` are
|
|
227
|
+
package-specific development dependencies merged over the generated baseline, and may carry any
|
|
228
|
+
valid npm package name.
|
|
229
|
+
|
|
230
|
+
`bin`, `integration`, and `service` are the three structural axes, and they obey one law: each is
|
|
231
|
+
`true` only when the workspace physically ships the directory that defines it — never because of
|
|
232
|
+
the workspace's name, and never because a sibling axis is set. `deriveBlueprint` probes exactly
|
|
233
|
+
those directories, so a fresh compile and an audit of a mature repository agree on what the
|
|
234
|
+
workspace is.
|
|
235
|
+
|
|
236
|
+
- **`bin`** — `src/bin/` exists. It alone turns on the self-hosting extras: the manifest's `bin`
|
|
237
|
+
entry, the `scaffold` script pointed at the built executable, the bin check, test, and build
|
|
238
|
+
scripts, `build:host`, the `configs/src/tsconfig.bin.json` and `configs/src/vite.bin.config.ts`
|
|
239
|
+
artifacts, and the `src:bin` test project.
|
|
240
|
+
- **`integration`** — `tests/integration/` exists. It records a slow, opt-in proof project over the
|
|
241
|
+
workspace's own built output, outside the default run: the generated root configuration registers
|
|
242
|
+
a standalone `integration` project including `tests/integration/**/*.test.ts`, and the manifest
|
|
243
|
+
emits `test:integration`.
|
|
244
|
+
- **`service`** — `tests/service/` exists. It records a slow, opt-in proof project against a foreign
|
|
245
|
+
running process, outside the default run: a standalone `service` project including
|
|
246
|
+
`tests/service/**/*.test.ts`, with `tests/setupService.ts` after the shared setup, and the
|
|
247
|
+
isolated `test:service` script.
|
|
248
|
+
|
|
249
|
+
A service workspace owes two companion files beside that directory, and derivation requires both
|
|
250
|
+
physically present: `tests/setupService.ts` and `scripts/service.sh`. Either missing companion is a
|
|
251
|
+
coded `TARGET` failure naming the missing path rather than a silent `service: false`. This package
|
|
252
|
+
emits neither: both are consumer-owned seams, and the generated-workspace section sets out what
|
|
253
|
+
each owes its workspace and which proof runs in which gate. Nothing here is inferred — the
|
|
254
|
+
executable axis turns on neither proof project, and neither proof project turns on the other.
|
|
221
255
|
|
|
222
256
|
`Override` replaces a rendered artifact's content at a path, never partially merges it. `Member` is
|
|
223
257
|
one declared public export of the scaffolded workspace, derived rather than authored.
|
|
@@ -322,8 +356,10 @@ From [`constants.ts`](../../src/core/constants.ts).
|
|
|
322
356
|
| `FRESHNESS` | const |
|
|
323
357
|
| `COMPILE_STAGES` | const |
|
|
324
358
|
| `SRC_MATRIX` | const |
|
|
359
|
+
| `BIN_CONFIGS` | const |
|
|
325
360
|
| `APP_MATRIX` | const |
|
|
326
361
|
| `HOST_PATHS` | const |
|
|
362
|
+
| `SERVICE_SCRIPT_PATH` | const |
|
|
327
363
|
| `NAME_PATTERN` | const |
|
|
328
364
|
| `MAX_NAME_LENGTH` | const |
|
|
329
365
|
| `MAX_DEPENDENCY_NAME_LENGTH` | const |
|
|
@@ -368,11 +404,13 @@ From [`constants.ts`](../../src/core/constants.ts).
|
|
|
368
404
|
`ENVIRONMENTS`, `ORIGINS`, `GROUPS`, `CATEGORIES`, `FRESHNESS`, and `COMPILE_STAGES` are the frozen
|
|
369
405
|
value lists behind their literal unions. `SRC_MATRIX` is the `src` environment matrix as
|
|
370
406
|
data — each environment's `configs/src` files, test-project label, `exports` subpath, and build
|
|
371
|
-
formats. `APP_MATRIX` is its application sibling, adding the runtime entry where an environment
|
|
372
|
-
one (`app/browser/index.html`, `app/server/main.ts`). `
|
|
373
|
-
|
|
407
|
+
formats. `APP_MATRIX` is its application sibling, adding the runtime entry where an environment
|
|
408
|
+
produces one (`app/browser/index.html`, `app/server/main.ts`). `BIN_CONFIGS` is the executable
|
|
409
|
+
axis's computed `tsconfig` and Vite wrapper pair. `HOST_PATHS` is the ordered list of byte-copied
|
|
410
|
+
host artifacts, and it is the staging manifest rather than the per-plan carried set:
|
|
374
411
|
`stageHost` vendors every path on it, while each plan carries the subset `selectHostPaths` selects
|
|
375
|
-
for that one workspace.
|
|
412
|
+
for that one workspace. `SERVICE_SCRIPT_PATH` names the consumer-owned provisioner a service
|
|
413
|
+
workspace's audit expects.
|
|
376
414
|
|
|
377
415
|
The bounds are public because they are part of the contract, not implementation trivia.
|
|
378
416
|
`MAX_ARTIFACT_BYTES` caps one artifact at 5 MiB and `MAX_TOTAL_ARTIFACT_BYTES` caps one blueprint,
|
|
@@ -826,6 +864,7 @@ From [`helpers.ts`](../../src/server/helpers.ts).
|
|
|
826
864
|
| Name | Kind |
|
|
827
865
|
| -------------------------- | -------- |
|
|
828
866
|
| `isRealDirectory` | function |
|
|
867
|
+
| `isRealFile` | function |
|
|
829
868
|
| `digestFile` | function |
|
|
830
869
|
| `digestHex` | function |
|
|
831
870
|
| `digestText` | function |
|
|
@@ -888,7 +927,7 @@ so a file swapped mid-read is a failure rather than a silent wrong digest. `read
|
|
|
888
927
|
strictly, rejecting invalid UTF-8. Manifest reads stop at `MAX_MANIFEST_BYTES`; catalog guide reads
|
|
889
928
|
stop at `MAX_GUIDE_BYTES`. `listFiles` and `listDirectories` walk a real, unlinked root under the
|
|
890
929
|
entry and depth bounds, returning sorted POSIX-relative paths and `[]` for an absent root.
|
|
891
|
-
`isRealDirectory`
|
|
930
|
+
`isRealDirectory` and `isRealFile` are the physical path predicates they all lean on.
|
|
892
931
|
|
|
893
932
|
The write-transaction helpers are the fail-closed mutation path. `createWriteDirectory` establishes
|
|
894
933
|
a directory one segment at a time behind captured identities; `validateWriteAnchor`,
|
|
@@ -910,14 +949,17 @@ omitting an absent path entirely. `readManifest` reads `package.json` text, and
|
|
|
910
949
|
|
|
911
950
|
`deriveBlueprint` is the faithful inverse an audit needs: it reconstructs a blueprint from an
|
|
912
951
|
existing workspace so a mature package is diffed against its own would-be scaffold rather than a
|
|
913
|
-
dependency-less stand-in. Environments come from `src/<environment>/` and `app/<environment
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
952
|
+
dependency-less stand-in. Environments come from `src/<environment>/` and `app/<environment>/`, and
|
|
953
|
+
the three structural axes from the directory probes and the service companion law the blueprint
|
|
954
|
+
section states — every one of them a reading of the filesystem, never of the name. Dependencies and
|
|
955
|
+
peers come from the manifest's scoped entries, with an optional peer recovered from
|
|
956
|
+
`peerDependenciesMeta`; and `extras` is every development dependency minus the complete set
|
|
957
|
+
`devDependenciesFor` emits for those environments and structural axes, and minus anything already
|
|
958
|
+
declared as a dependency or peer. An axis-emitted dependency is therefore never double-counted,
|
|
959
|
+
while a hand-added development dependency round-trips and stays audit-clean. Derivation yields no
|
|
960
|
+
`overrides`: they are caller-time inputs, not repository state. A computed artifact that must differ
|
|
961
|
+
reveals a gap in the canon; the blueprint grows an axis for that distinction rather than the
|
|
962
|
+
repository forking the file.
|
|
921
963
|
|
|
922
964
|
`storagePath`, `stageHost`, `readHostManifest`, `locateHostSource`, `remapArtifactPath`, and
|
|
923
965
|
`hydratePlan` are the vendored-host path. `storagePath` maps a repo-relative path to its un-dotted
|
|
@@ -956,43 +998,52 @@ ordered guide and version outcomes.
|
|
|
956
998
|
|
|
957
999
|
From [`compilers.ts`](../../src/core/compilers.ts).
|
|
958
1000
|
|
|
959
|
-
| Name
|
|
960
|
-
|
|
|
961
|
-
| `hostGroup`
|
|
962
|
-
| `fillArtifact`
|
|
963
|
-
| `srcVariant`
|
|
964
|
-
| `entryFields`
|
|
965
|
-
| `dualCondition`
|
|
966
|
-
| `exportsMap`
|
|
967
|
-
| `compareCodeUnit`
|
|
968
|
-
| `devDependenciesFor`
|
|
969
|
-
| `packageManifest`
|
|
970
|
-
| `rootTsconfig`
|
|
971
|
-
| `viteMachinery`
|
|
972
|
-
| `
|
|
973
|
-
| `
|
|
974
|
-
| `
|
|
975
|
-
| `
|
|
976
|
-
| `
|
|
977
|
-
| `
|
|
978
|
-
| `
|
|
979
|
-
| `
|
|
980
|
-
| `
|
|
981
|
-
| `
|
|
982
|
-
| `
|
|
983
|
-
| `
|
|
984
|
-
| `
|
|
985
|
-
| `
|
|
986
|
-
| `
|
|
987
|
-
| `
|
|
988
|
-
| `
|
|
989
|
-
| `
|
|
990
|
-
| `
|
|
991
|
-
| `
|
|
992
|
-
| `
|
|
993
|
-
| `
|
|
994
|
-
| `
|
|
995
|
-
| `
|
|
1001
|
+
| Name | Kind |
|
|
1002
|
+
| -------------------------- | -------- |
|
|
1003
|
+
| `hostGroup` | function |
|
|
1004
|
+
| `fillArtifact` | function |
|
|
1005
|
+
| `srcVariant` | function |
|
|
1006
|
+
| `entryFields` | function |
|
|
1007
|
+
| `dualCondition` | function |
|
|
1008
|
+
| `exportsMap` | function |
|
|
1009
|
+
| `compareCodeUnit` | function |
|
|
1010
|
+
| `devDependenciesFor` | function |
|
|
1011
|
+
| `packageManifest` | function |
|
|
1012
|
+
| `rootTsconfig` | function |
|
|
1013
|
+
| `viteMachinery` | function |
|
|
1014
|
+
| `renderViteTest` | function |
|
|
1015
|
+
| `viteHeader` | function |
|
|
1016
|
+
| `policyViteProject` | function |
|
|
1017
|
+
| `guidesViteProject` | function |
|
|
1018
|
+
| `binViteProject` | function |
|
|
1019
|
+
| `integrationViteProject` | function |
|
|
1020
|
+
| `serviceViteProject` | function |
|
|
1021
|
+
| `viteProjectRegistrations` | function |
|
|
1022
|
+
| `viteProjectDefinitions` | function |
|
|
1023
|
+
| `singleSrcViteConfig` | function |
|
|
1024
|
+
| `rootViteConfig` | function |
|
|
1025
|
+
| `applicationViteConfig` | function |
|
|
1026
|
+
| `coreTsconfig` | function |
|
|
1027
|
+
| `coreViteConfig` | function |
|
|
1028
|
+
| `srcTsconfig` | function |
|
|
1029
|
+
| `srcViteConfig` | function |
|
|
1030
|
+
| `binTsconfig` | function |
|
|
1031
|
+
| `binViteConfig` | function |
|
|
1032
|
+
| `appTsconfig` | function |
|
|
1033
|
+
| `appViteConfig` | function |
|
|
1034
|
+
| `ciWorkflow` | function |
|
|
1035
|
+
| `configArtifacts` | function |
|
|
1036
|
+
| `sourceArtifacts` | function |
|
|
1037
|
+
| `applicationArtifacts` | function |
|
|
1038
|
+
| `paritySpecifiers` | function |
|
|
1039
|
+
| `testArtifacts` | function |
|
|
1040
|
+
| `guideMemberTable` | function |
|
|
1041
|
+
| `guideUsage` | function |
|
|
1042
|
+
| `guideMethods` | function |
|
|
1043
|
+
| `guideTests` | function |
|
|
1044
|
+
| `guideArtifacts` | function |
|
|
1045
|
+
| `applyOverrides` | function |
|
|
1046
|
+
| `blueprintToPlan` | function |
|
|
996
1047
|
|
|
997
1048
|
`blueprintToPlan` is the whole pure compilation: draft each selected group's artifacts, append the
|
|
998
1049
|
host set, apply overrides, and pin. Everything above it is an exported leaf of that drafting, each
|
|
@@ -1002,10 +1053,11 @@ independently callable and independently tested.
|
|
|
1002
1053
|
several. `entryFields`, `dualCondition`, and `exportsMap` build the manifest entry fields and the
|
|
1003
1054
|
`exports` map from that variant; a browser-only package exports a single module condition, while
|
|
1004
1055
|
core and server src get dual import and require conditions with matching declaration files.
|
|
1005
|
-
`devDependenciesFor`
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1056
|
+
`devDependenciesFor` emits the blueprint's complete development dependency set: the shared
|
|
1057
|
+
baseline, package extras, dev-installed peers, selected browser toolchains, and the bin axis's
|
|
1058
|
+
browser test provider. Extras and peers are sorted by `compareCodeUnit` so ordering is stable across
|
|
1059
|
+
locales. `packageManifest` assembles the whole file — name, publication mode, files, scripts,
|
|
1060
|
+
dependencies, peers and their optional metadata, and engines.
|
|
1009
1061
|
|
|
1010
1062
|
`rootTsconfig` emits the root compiler options and one path alias per declared environment;
|
|
1011
1063
|
`coreTsconfig`, `srcTsconfig`, and `appTsconfig` emit the scoped configurations that remove the
|
|
@@ -1027,7 +1079,8 @@ emits `environmentBoundary`, its `resolveId` / `load` / `buildEnd` walks, the mo
|
|
|
1027
1079
|
plus its `environmentPathError` / `environmentSourceError` clauses). Those enforce owner-independent
|
|
1028
1080
|
laws: core stays host-independent whatever else the workspace declares, a server module never
|
|
1029
1081
|
imports a stylesheet, and a `@vite-ignore` dynamic import — which `resolveId` never sees and the
|
|
1030
|
-
module graph never records — has no other enforcement point
|
|
1082
|
+
module graph never records — has no other enforcement point in workspace-owned source. Dependency
|
|
1083
|
+
and toolchain modules are outside that ownership boundary. Only host-specific pipelines vary,
|
|
1031
1084
|
along the three `ViteMachinery` axes:
|
|
1032
1085
|
|
|
1033
1086
|
| Machinery | Emitted when |
|
|
@@ -1040,13 +1093,36 @@ along the three `ViteMachinery` axes:
|
|
|
1040
1093
|
An application of `app/core` alone is the sole shape that builds nothing, so it is the sole shape
|
|
1041
1094
|
without output containment — and it still carries every boundary guarantee above.
|
|
1042
1095
|
|
|
1043
|
-
`
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
`
|
|
1096
|
+
`renderViteTest` is the single root-project renderer. It consumes ordered `ViteProjectRegistration`
|
|
1097
|
+
data and emits either the plain project list or the browser gate, keeping source and application
|
|
1098
|
+
root configurations byte-consistent without reconstructing browser ownership.
|
|
1099
|
+
`viteProjectRegistrations` is the one registration derivation every root shape consumes: it derives
|
|
1100
|
+
the selected source and application projects from the canonical environment order, then appends
|
|
1101
|
+
`policy`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
|
|
1102
|
+
`viteProjectDefinitions` renders the standalone proof and structural-axis definitions in that same
|
|
1103
|
+
order with one blank line between declarations. Both consume `ViteAxes`, so each optional project is
|
|
1104
|
+
controlled only by its matching `bin`, `integration`, or `service` blueprint axis.
|
|
1105
|
+
|
|
1106
|
+
`coreViteConfig`, `srcViteConfig`, `binViteConfig`, and `appViteConfig` emit the thin per-target
|
|
1107
|
+
wrappers, while `binTsconfig` emits the executable declaration scope; `rootViteConfig`,
|
|
1108
|
+
`singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for a library-only,
|
|
1109
|
+
single non-core `src` environment, and application-bearing workspace respectively; and
|
|
1110
|
+
`policyViteProject`, `guidesViteProject`, `integrationViteProject`, and `serviceViteProject` emit
|
|
1111
|
+
the standalone Node proof projects, with `binViteProject` the single executable-project emitter. A
|
|
1112
|
+
proof project is structurally derived from the directory holding its tests and never wraps a source
|
|
1113
|
+
or application environment project. The guides project therefore uses only `tests/setup.ts`, never
|
|
1114
|
+
`setupServer.ts`, `setupBrowser.ts`, or `setupService.ts`; and its `tests/src/**/*.test.ts` and
|
|
1115
|
+
`tests/app/**/*.test.ts` exclude rows are uniform across all root shapes by design, including
|
|
1116
|
+
core-only workspaces where one row cannot currently match. Integration and service use 120-second
|
|
1117
|
+
test and hook timeouts with file parallelism disabled, and service alone layers
|
|
1118
|
+
`tests/setupService.ts` onto the shared setup. Where a bin workspace also ships the integration
|
|
1119
|
+
project, that project wires `tests/setupIntegration.ts` as its global setup for the shared
|
|
1120
|
+
template-registry harness; bin-less integration workspaces do not.
|
|
1047
1121
|
|
|
1048
1122
|
`configArtifacts`, `sourceArtifacts`, `applicationArtifacts`, `testArtifacts`, and `guideArtifacts`
|
|
1049
|
-
are the per-group drafters. `
|
|
1123
|
+
are the per-group drafters. When `bin` is selected, `configArtifacts` includes
|
|
1124
|
+
`configs/src/tsconfig.bin.json` and `configs/src/vite.bin.config.ts` beside the declared environment
|
|
1125
|
+
configuration pairs. `paritySpecifiers` computes the self-specifier and module map the
|
|
1050
1126
|
generated parity suite resolves fence imports through. `guideMemberTable`, `guideUsage`,
|
|
1051
1127
|
`guideMethods`, and `guideTests` render the generated guide's member tables, usage examples, method
|
|
1052
1128
|
contract, and test inventory. `fillArtifact` fills one template entry into a `template`-origin
|
|
@@ -1275,13 +1351,13 @@ Audit semantics follow directly from that.
|
|
|
1275
1351
|
- A target file the plan does not own is `foreign`, and `inferGroup` classifies it by its leading
|
|
1276
1352
|
path segment.
|
|
1277
1353
|
|
|
1278
|
-
The same ownership boundary is what makes mutation safe. **`
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
`.github/workflows/ci.yml` is a **computed** artifact,
|
|
1283
|
-
|
|
1284
|
-
|
|
1354
|
+
The same ownership boundary is what makes mutation safe. **`fleet` and default `repair` both scope
|
|
1355
|
+
the compiled plan to host origin before hydrating, diffing, or applying.** `--generated` widens that
|
|
1356
|
+
scoped plan to generated canon except `package.json`; template artifacts remain birth-only in
|
|
1357
|
+
either mode. A mature workspace's hand-written source, tests, guides, and manifest are therefore
|
|
1358
|
+
never overwritten with a stub. The generated `.github/workflows/ci.yml` is a **computed** artifact,
|
|
1359
|
+
so user-owned CI stands by default but is intentionally restored when `--generated` is passed.
|
|
1360
|
+
Audit always compares it because computed artifacts are content-aware canon. A legitimate
|
|
1285
1361
|
difference that the blueprint cannot express is a canon gap: add the missing blueprint axis rather
|
|
1286
1362
|
than forking the computed file in one repository.
|
|
1287
1363
|
|
|
@@ -1313,12 +1389,20 @@ An audit is a pure function of a plan and a snapshot, so the same engine that cr
|
|
|
1313
1389
|
checks one. `readTarget` supplies the snapshot as exact bytes; `diffPlan` returns findings as data;
|
|
1314
1390
|
`auditToReview` renders them for a human. Nothing in that path writes.
|
|
1315
1391
|
|
|
1392
|
+
The executable's physical unexpected-file scan treats exactly `scripts/service.sh` as an expected
|
|
1393
|
+
consumer-owned seam when the derived blueprint has `service: true`. That exclusion is warranted
|
|
1394
|
+
because a service blueprint cannot derive without the physical file: the companion-file law raises
|
|
1395
|
+
a `TARGET` failure first, so the scan removes a false positive and can never mask an absent
|
|
1396
|
+
provisioner. A non-service workspace still reports the same path as foreign.
|
|
1397
|
+
|
|
1316
1398
|
`repair` turns those findings back into the narrowest possible write. It re-reads the target,
|
|
1317
1399
|
re-diffs it, and refuses to proceed if the findings changed since the preview it was given — a
|
|
1318
1400
|
target that moved under the caller is a `TARGET` failure, not a race to win. It then derives a write
|
|
1319
1401
|
precondition per artifact from the audit itself: a `missing` finding requires the destination to
|
|
1320
1402
|
still be absent, a `stale` finding requires it to still carry exactly the bytes that were observed.
|
|
1321
1403
|
Those preconditions are checked again inside the write transaction before any promotion.
|
|
1404
|
+
An interactive audit repair hand-off forwards `--generated` into the repair invocation when the
|
|
1405
|
+
flag was present on `audit`.
|
|
1322
1406
|
|
|
1323
1407
|
`prune` is the deletion arm, and it is deliberately narrow. Its candidate set comes from
|
|
1324
1408
|
`pruneTargets`, which is also what the executable's audit and preview read, so what is reported and
|
|
@@ -1389,20 +1473,65 @@ configuration, and ships `dist/src` plus its README. An application-only workspa
|
|
|
1389
1473
|
that builds its own executable additionally ships `dist/bin` and `dist/host`. Scripts are emitted in
|
|
1390
1474
|
a fixed, interleaved order so aggregates sit immediately before their per-environment members:
|
|
1391
1475
|
|
|
1392
|
-
- `clean`, `copy`, `scaffold`
|
|
1393
|
-
- `lint` and `lint:check`, `format` and `format:check`
|
|
1476
|
+
- `clean`, `copy`, `scaffold`, `lint`
|
|
1394
1477
|
- `check`, then `check:src` with one `check:src:<environment>` per published environment, then
|
|
1395
1478
|
`check:app` with one `check:app:<environment>` per app environment — the browser app scope uses the
|
|
1396
1479
|
Vue typechecker, every other scope uses plain `tsc`
|
|
1397
|
-
- `
|
|
1398
|
-
|
|
1399
|
-
`test:
|
|
1480
|
+
- `format`, `format:check`, `lint:check`
|
|
1481
|
+
- `test`, then `test:src` and its per-environment scopes, the optional `test:integration`,
|
|
1482
|
+
`test:equivalence`, and `test:service` proofs, `test:app` and its per-environment scopes, then
|
|
1483
|
+
`test:policy` and `test:guides`
|
|
1400
1484
|
- `build`, then `build:src` and its per-environment targets, `build:app` and its runtime targets, and
|
|
1401
|
-
`build:host` for
|
|
1485
|
+
`build:host` for a bin workspace
|
|
1402
1486
|
- `dev` when a browser application is selected; `serve` and `serve:build` when a server application
|
|
1403
1487
|
is selected
|
|
1404
|
-
- `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by
|
|
1405
|
-
|
|
1488
|
+
- `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by
|
|
1489
|
+
`test:integration` when the integration axis is selected
|
|
1490
|
+
|
|
1491
|
+
**Proof gating.** The opt-in proofs are predictable from the axes alone. `test:integration` rides
|
|
1492
|
+
the `integration` axis and `test:service` the `service` axis, while `test:equivalence` is emitted
|
|
1493
|
+
only where `bin` and `integration` are both set:
|
|
1494
|
+
|
|
1495
|
+
| Proof | `npm test` | `prepublishOnly` | CI |
|
|
1496
|
+
| ------------------ | ---------- | ---------------- | -------------------------- |
|
|
1497
|
+
| `test:integration` | no | yes, last | after the standard gates |
|
|
1498
|
+
| `test:equivalence` | no | no | no |
|
|
1499
|
+
| `test:service` | no | never | after `scripts/service.sh` |
|
|
1500
|
+
|
|
1501
|
+
No proof joins the default chain: `npm test` runs the source, application, policy, and guide
|
|
1502
|
+
projects, and nothing there needs a build artifact or a foreign process. Publication is the one
|
|
1503
|
+
asymmetry — `prepublishOnly` appends `test:integration`, because a package about to be published
|
|
1504
|
+
should prove itself against its own built output, while `test:service` is never in that chain.
|
|
1505
|
+
Neither default testing nor publication starts or requires a foreign process.
|
|
1506
|
+
|
|
1507
|
+
When a prerequisite is absent the proof fails rather than skipping. `test:integration` reads the
|
|
1508
|
+
workspace's own built output, so it belongs after `build` — which is exactly where `prepublishOnly`
|
|
1509
|
+
and CI put it. `test:service` refuses to start against an unprovisioned service: its setup throws at
|
|
1510
|
+
module load, which is why CI runs `bash scripts/service.sh` immediately before it. And a script the
|
|
1511
|
+
axes do not emit is simply not there: `test:equivalence` in a workspace that is not both `bin` and
|
|
1512
|
+
`integration` is an unknown script rather than a quietly passing one.
|
|
1513
|
+
|
|
1514
|
+
The equivalence proof is a dual-path re-run rather than a separate suite. Run
|
|
1515
|
+
`npm run test:equivalence` after changing the persistent boundary build driver; it invokes the
|
|
1516
|
+
integration project in dual-path mode and proves each programmatic driver verdict against the
|
|
1517
|
+
spawned npm-script reference. Ordinary integration runs keep the faster driver-only path.
|
|
1518
|
+
|
|
1519
|
+
**Consumer-owned service seams.** The service axis is the one place canon stops at the boundary:
|
|
1520
|
+
there is no template for a proof project and neither companion path is on `HOST_PATHS`, so a
|
|
1521
|
+
service workspace owns both of its seams outright. They come as a pair.
|
|
1522
|
+
|
|
1523
|
+
- `tests/setupService.ts` is the readiness seam. It probes the foreign process and warms it before
|
|
1524
|
+
any test runs, and throws at module load — naming the `service` project — when that process is
|
|
1525
|
+
unreachable, so an unprovisioned run fails loudly instead of passing an empty suite. Only the
|
|
1526
|
+
`service` project loads it.
|
|
1527
|
+
- `scripts/service.sh` is the provisioning seam, named once by `SERVICE_SCRIPT_PATH`. It brings that
|
|
1528
|
+
process up idempotently — a second run against an already-provisioned service is a no-op rather
|
|
1529
|
+
than a second instance — and exits nonzero when it cannot, which is what makes CI's
|
|
1530
|
+
`bash scripts/service.sh` step a gate rather than a hint.
|
|
1531
|
+
|
|
1532
|
+
The audit expects the script rather than reporting it foreign, on the derive-time warrant the audit
|
|
1533
|
+
section gives. Repair pruning applies the same exclusion, so it never proposes or removes that
|
|
1534
|
+
required consumer-owned provisioner.
|
|
1406
1535
|
|
|
1407
1536
|
**Environment isolation.** Scoped TypeScript projects remove the wrong host's globals from each
|
|
1408
1537
|
environment: core scopes carry the WHATWG web-interop surface and no host at all — no DOM, no Node,
|
|
@@ -1451,10 +1580,10 @@ application's module graph through `import.meta.env` instead.
|
|
|
1451
1580
|
Asset URLs that force `?inline` are rejected before Vite can read them outside that auditable output
|
|
1452
1581
|
graph. Dynamic imports must use a static quoted string or expression-free template string; even
|
|
1453
1582
|
`/* @vite-ignore */` static values repeat the same environment and containment checks inside the
|
|
1454
|
-
transform boundary, including inline HTML proxy modules
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1583
|
+
transform boundary, including inline HTML proxy modules. The transform, load, resolution, emitted
|
|
1584
|
+
asset, and finished-module-graph passes apply that law only to workspace-owned `src/*` and `app/*`
|
|
1585
|
+
modules. Resolved ids under any `node_modules` segment, Vite/Vitest virtual ids, and tooling client
|
|
1586
|
+
injections remain owned by their toolchain and are exempt.
|
|
1458
1587
|
|
|
1459
1588
|
Browser application scripts are modules. Vite's parsed HTML asset callback rejects a classic
|
|
1460
1589
|
external `<script src>` before resolution and directs the author to `type="module"`. A module
|
|
@@ -1469,9 +1598,9 @@ path remains Vite-owned and passes through the environment resolver, which rejec
|
|
|
1469
1598
|
ASCII control range and every non-Node URL scheme before loading or output. No second HTML parser or global
|
|
1470
1599
|
reference rewrite is involved, so comments, text, non-script attributes, and entity-spelled asset
|
|
1471
1600
|
filenames retain Vite's native parsing and resolution behavior.
|
|
1472
|
-
The resolver leaves NUL-prefixed Rolldown/Vite
|
|
1473
|
-
|
|
1474
|
-
|
|
1601
|
+
The resolver leaves NUL-prefixed and `virtual:` Rolldown/Vite module IDs, tooling client injections,
|
|
1602
|
+
and every resolved `node_modules` module to the tool that owns that namespace; author module and
|
|
1603
|
+
asset URLs are extracted and validated before they reach those resolver exceptions.
|
|
1475
1604
|
SVG script `href` and `xlink:href` attributes are parsed too and rejected as classic script loads.
|
|
1476
1605
|
Inline module scripts enter Vite's HTML proxy graph and receive the same Oxc boundary analysis as
|
|
1477
1606
|
module files. Classic inline scripts cannot enter that graph, so the required security prologue places
|
|
@@ -1511,11 +1640,7 @@ What it rejects is equally deliberate:
|
|
|
1511
1640
|
browser or server package subpath;
|
|
1512
1641
|
- a browser module reaching a Node builtin or a server subpath;
|
|
1513
1642
|
- a server module reaching a stylesheet, Vue, or a browser subpath;
|
|
1514
|
-
- a workspace-relative import that resolves outside the workspace
|
|
1515
|
-
escapes the exact physical package root established by the nearest bounded, unlinked
|
|
1516
|
-
`package.json` whose own `name` exactly matches the resolved dependency;
|
|
1517
|
-
- a package `#imports` mapping that resolves outside both the declaring package and another exact
|
|
1518
|
-
physical package root;
|
|
1643
|
+
- a workspace-relative import that resolves outside the workspace;
|
|
1519
1644
|
- an HTML reference carrying `vite-ignore` that violates the same environment or containment law
|
|
1520
1645
|
as an ordinary reference, a Vite `%ENV%` HTML substitution, a classic external script, or a
|
|
1521
1646
|
computed dynamic import in the module graph that would bypass graph resolution;
|
|
@@ -1549,11 +1674,14 @@ host-origin file and run it as a dedicated Node-only `policy` test project over
|
|
|
1549
1674
|
**Real browser capability.** Browser test projects are gated on the real executable: the generated
|
|
1550
1675
|
configuration and the generated policy test both probe `existsSync(chromium.executablePath())`. A
|
|
1551
1676
|
browser suite runs when a real Chromium is installed and is skipped honestly when it is not, rather
|
|
1552
|
-
than being faked. The gate is applied at registration, not
|
|
1553
|
-
Chromium
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1677
|
+
than being faked. The gate is applied at registration, not inside the real browser project: without
|
|
1678
|
+
Chromium, each browser factory is replaced by a same-label Node/no-test placeholder, so generated
|
|
1679
|
+
`--project <label>` and `--project=<label>` filters still resolve while no browser code runs. The
|
|
1680
|
+
root permits an empty run only when every recognized exact project filter names one of those gated
|
|
1681
|
+
placeholders; an unreadable or mixed filter keeps the ordinary no-test failure semantics for its
|
|
1682
|
+
Node projects. One printed warning names every gated project label. A machine with a browser
|
|
1683
|
+
registers and runs the real browser suites unchanged; a machine without one runs the remaining
|
|
1684
|
+
projects and says so.
|
|
1557
1685
|
|
|
1558
1686
|
**Continuous integration.** The generated workflow runs on push and pull request, on
|
|
1559
1687
|
`ubuntu-latest`, with read-only contents permission, a 60-minute timeout, and a matrix that **tests
|
|
@@ -1561,7 +1689,8 @@ Node `22.12.0` and `26`** with fail-fast disabled. Checkout and Node setup are p
|
|
|
1561
1689
|
action commits, and checkout does not persist credentials. Dependencies install with
|
|
1562
1690
|
`npm ci --ignore-scripts`; Chromium is installed only when the workspace selects a browser environment
|
|
1563
1691
|
or builds its own executable. The gates then run in order: `format:check`, `lint:check`, `check`,
|
|
1564
|
-
`build`, `test
|
|
1692
|
+
`build`, `test`, and the workspace's selected proofs follow as their own named steps, in the order
|
|
1693
|
+
the proof-gating table gives them.
|
|
1565
1694
|
|
|
1566
1695
|
**Agent orchestration files.** The session hooks in the generated `.claude/settings.json` run the
|
|
1567
1696
|
dependency, model, and external-tool readiness scripts at session start. The **`Stop` hook runs only
|
|
@@ -1590,7 +1719,7 @@ no module API of its own. Six verbs:
|
|
|
1590
1719
|
| `new` | scaffold a workspace into `./<name>` |
|
|
1591
1720
|
| `pull` | refresh vendored guides and versions, report drift |
|
|
1592
1721
|
| `audit` | whole-plan conformance report |
|
|
1593
|
-
| `repair` | restore
|
|
1722
|
+
| `repair` | restore host-owned files and optional generated canon |
|
|
1594
1723
|
| `fleet` | audit or repair every workspace under the cwd's children |
|
|
1595
1724
|
| `catalog` | regenerate the fleet package-catalog table |
|
|
1596
1725
|
|
|
@@ -1611,8 +1740,10 @@ declared dependency mirror is considered.
|
|
|
1611
1740
|
`--groups a,b` scopes an audit to artifact groups. `--live` adds an upstream freshness check to an
|
|
1612
1741
|
audit. `--strict` makes a pull throw on a network fault. `--offline` restricts a catalog to local
|
|
1613
1742
|
sources. `--prune` opts a repair or fleet run into deleting unexpected files under the three prune
|
|
1614
|
-
directories. `--
|
|
1615
|
-
|
|
1743
|
+
directories. `--generated` opts a repair or fleet run into restoring generated canon except
|
|
1744
|
+
`package.json`; on `audit`, it is inherited if the interactive repair hand-off is accepted.
|
|
1745
|
+
`--json` emits one machine-readable value. `--apply` writes, `--yes` skips the confirmation, and
|
|
1746
|
+
`-h` or `--help` prints usage.
|
|
1616
1747
|
|
|
1617
1748
|
**Safety model.** Every verb is a dry run by default. On a terminal a write asks for confirmation
|
|
1618
1749
|
first, defaulting to no; in a script, `--apply` writes and `--yes` skips the question. Every write is
|
|
@@ -1622,8 +1753,9 @@ non-interactive session without `--apply` or `--yes` skips pruning rather than g
|
|
|
1622
1753
|
operates on the immediate children of the working directory and never on the directory itself, and
|
|
1623
1754
|
it has no root flag at all — `repair` is the single-workspace tool.
|
|
1624
1755
|
|
|
1625
|
-
|
|
1626
|
-
in
|
|
1756
|
+
`fleet` and default `repair` are scoped to host-origin artifacts. `repair` states its selected scope
|
|
1757
|
+
in the output; `--generated` widens both verbs to generated files while still excluding starter
|
|
1758
|
+
files and `package.json`.
|
|
1627
1759
|
|
|
1628
1760
|
**Catalog markers.** `catalog` rewrites the block between `<!-- catalog:start -->` and
|
|
1629
1761
|
`<!-- catalog:end -->` in `.claude/agents/orkestrel.md`. **Ambiguous markers fail before any
|
|
@@ -1976,7 +2108,7 @@ srcVariant(['core', 'server']) // 'multi'
|
|
|
1976
2108
|
entryFields(['browser']).main // './dist/src/browser/index.js'
|
|
1977
2109
|
dualCondition('./dist/src/core/index')
|
|
1978
2110
|
exportsMap(['core'])['.']
|
|
1979
|
-
devDependenciesFor(spec
|
|
2111
|
+
devDependenciesFor(spec).typescript
|
|
1980
2112
|
packageManifest(spec) // the whole manifest, newline-terminated
|
|
1981
2113
|
|
|
1982
2114
|
configArtifacts(spec).length
|
|
@@ -2006,16 +2138,23 @@ import {
|
|
|
2006
2138
|
appTsconfig,
|
|
2007
2139
|
appViteConfig,
|
|
2008
2140
|
applicationViteConfig,
|
|
2141
|
+
binViteProject,
|
|
2009
2142
|
coreTsconfig,
|
|
2010
2143
|
coreViteConfig,
|
|
2144
|
+
guidesViteProject,
|
|
2145
|
+
integrationViteProject,
|
|
2011
2146
|
policyViteProject,
|
|
2147
|
+
renderViteTest,
|
|
2012
2148
|
rootTsconfig,
|
|
2013
2149
|
rootViteConfig,
|
|
2150
|
+
serviceViteProject,
|
|
2014
2151
|
singleSrcViteConfig,
|
|
2015
2152
|
srcTsconfig,
|
|
2016
2153
|
srcViteConfig,
|
|
2017
2154
|
viteHeader,
|
|
2018
2155
|
viteMachinery,
|
|
2156
|
+
viteProjectDefinitions,
|
|
2157
|
+
viteProjectRegistrations,
|
|
2019
2158
|
} from '@orkestrel/scaffold'
|
|
2020
2159
|
|
|
2021
2160
|
rootTsconfig(['core'], ['core', 'server'])
|
|
@@ -2025,13 +2164,21 @@ appTsconfig('browser', true)
|
|
|
2025
2164
|
|
|
2026
2165
|
viteMachinery(['core']) // { browser: false, vue: false, output: true }
|
|
2027
2166
|
viteMachinery([], ['core', 'browser']) // { browser: true, vue: true, output: true }
|
|
2167
|
+
renderViteTest([{ project: 'srcCore' }], false).includes('projects: [srcCore]') // true
|
|
2028
2168
|
viteHeader(viteMachinery([], ['core', 'browser'])) // the shared header, with browser and Vue support
|
|
2029
2169
|
coreViteConfig()
|
|
2030
2170
|
srcViteConfig('browser')
|
|
2031
2171
|
appViteConfig('server')
|
|
2032
2172
|
policyViteProject()
|
|
2033
|
-
|
|
2034
|
-
|
|
2173
|
+
guidesViteProject()
|
|
2174
|
+
binViteProject()
|
|
2175
|
+
integrationViteProject({ bin: true, integration: true })
|
|
2176
|
+
serviceViteProject()
|
|
2177
|
+
viteProjectDefinitions({ integration: true }).includes('export const integration =') // true
|
|
2178
|
+
viteProjectRegistrations(['core'], [], { integration: true }).map(({ project }) => project)
|
|
2179
|
+
// ['srcCore', 'policy', 'guides', 'integration']
|
|
2180
|
+
|
|
2181
|
+
rootViteConfig(['core', 'server'], { bin: true })
|
|
2035
2182
|
singleSrcViteConfig('server').includes('srcServer') // true
|
|
2036
2183
|
applicationViteConfig([], ['core', 'server']).includes('appServer') // true
|
|
2037
2184
|
```
|
|
@@ -2136,6 +2283,7 @@ import {
|
|
|
2136
2283
|
discoverPackages,
|
|
2137
2284
|
guideToDescription,
|
|
2138
2285
|
isRealDirectory,
|
|
2286
|
+
isRealFile,
|
|
2139
2287
|
listDirectories,
|
|
2140
2288
|
listFiles,
|
|
2141
2289
|
pruneTargets,
|
|
@@ -2150,6 +2298,7 @@ deriveBlueprint('./packages/router') // the faithful inverse an audit diffs agai
|
|
|
2150
2298
|
selectOrkestrelEntries({ '@orkestrel/contract': '^0.0.7', vite: '^8.1.5' })
|
|
2151
2299
|
|
|
2152
2300
|
isRealDirectory('./packages/router')
|
|
2301
|
+
isRealFile('./packages/router/package.json')
|
|
2153
2302
|
listFiles('./packages/router/.claude/agents')
|
|
2154
2303
|
listDirectories('./packages/router/.claude')
|
|
2155
2304
|
|