@orkestrel/scaffold 0.0.50 → 0.0.51
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/main.js +46 -17
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +2 -2
- package/dist/host/agents/orchestration.md +14 -12
- package/dist/host/claude/agents/orkestrel.md +10 -10
- package/dist/host/claude/rules/architecture.md +6 -6
- package/dist/host/claude/rules/tests.md +4 -2
- package/dist/host/claude/rules/workspace.md +1 -1
- package/dist/host/codex/config.toml +1 -1
- package/dist/host/guides/scaffold.md +48 -44
- package/dist/host/manifest.json +10 -10
- package/dist/host/tests/config.test.ts +57 -0
- package/dist/src/core/index.cjs +452 -405
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +51 -48
- package/dist/src/core/index.d.ts +51 -48
- package/dist/src/core/index.js +452 -405
- package/dist/src/core/index.js.map +1 -1
- package/package.json +1 -1
package/dist/host/AGENTS.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
- External delegates, including Cursor and Codex models, have no exemption. Every dispatch restates the non-negotiables, applicable rules, guide or spec, and owned files. Every result receives independent review.
|
|
14
14
|
- Before working, read in order:
|
|
15
15
|
1. this file;
|
|
16
|
-
2. every applicable file in `.claude/rules/` from the
|
|
16
|
+
2. every applicable file in `.claude/rules/` from the Rule map section;
|
|
17
17
|
3. every explicitly invoked or dispatch-named skill and the references it requires;
|
|
18
18
|
4. `guides/README.md`, the matching guide or spec, and `ROADMAP.md` when present.
|
|
19
19
|
- Rules state **how to write**. Guides and specs state **what to build** and the domain workflow. When they conflict, stop and surface the conflict.
|
|
@@ -115,7 +115,7 @@ npm run format:check → npm run lint:check → npm run check → npm run build
|
|
|
115
115
|
|
|
116
116
|
## Rule map
|
|
117
117
|
|
|
118
|
-
Every file
|
|
118
|
+
Every file in the following table is a normative extension of this root. Read every rule relevant to the files or concepts you touch. Path frontmatter only controls Claude's automatic loading.
|
|
119
119
|
|
|
120
120
|
| Rule | Governs |
|
|
121
121
|
| -------------------------------- | ---------------------------------------------------------------------- |
|
|
@@ -7,7 +7,7 @@ harness follows this file.
|
|
|
7
7
|
|
|
8
8
|
Read in this order before acting:
|
|
9
9
|
|
|
10
|
-
1. The user's current instruction. It wins over
|
|
10
|
+
1. The user's current instruction. It wins over every later item.
|
|
11
11
|
2. `AGENTS.md` and the applicable `.claude/rules/*.md` files. They govern code substance.
|
|
12
12
|
3. This file. It governs agent operation only and cannot weaken the coding contract.
|
|
13
13
|
4. The dispatch-named skill and the references it requires.
|
|
@@ -95,8 +95,9 @@ Record the substitution.
|
|
|
95
95
|
- Grok takes every lane only in Cursor, and only when Opus 5 and Sol are both unavailable.
|
|
96
96
|
- Treat a lane that returns no verdicts as a lane that did not run. A bench lane reporting that its
|
|
97
97
|
driver executed and its engine was never reached is a dark bench, not a result. Record the bench
|
|
98
|
-
dark from that report, re-run the lane on the substitute engine from the table
|
|
99
|
-
the routing ledger which lane ran on which engine. Never accept a round with one lane
|
|
98
|
+
dark from that report, re-run the lane on the substitute engine from the preceding table, and
|
|
99
|
+
name in the routing ledger which lane ran on which engine. Never accept a round with one lane
|
|
100
|
+
empty.
|
|
100
101
|
- Re-read bench liveness at dispatch, not at session start. A bench that probed live can be dark when
|
|
101
102
|
the lane launches.
|
|
102
103
|
|
|
@@ -288,13 +289,14 @@ owns each bench's exact probe.
|
|
|
288
289
|
|
|
289
290
|
The local steps still run, because they route the recovery rather than decide the verdict: an
|
|
290
291
|
unresolved CLI is an install problem, a failed authentication-state check starts the login ladder
|
|
291
|
-
|
|
292
|
-
can see. Record every dark bench with its fallback and the lane substitution
|
|
293
|
-
absorb one silently. A readiness script reports readiness and performs no
|
|
294
|
-
trip belongs to the Orchestrator's own probe or to the bridge carrying
|
|
295
|
-
Liveness also expires: a dispatch that fails on quota, model access,
|
|
296
|
-
liveness result rather than a unit-level fault, so record the bench dark
|
|
297
|
-
lane instead of re-dispatching against a session-start answer that no
|
|
292
|
+
in Recovering a dark bench, and a bench that passes both and still cannot round-trip is dark for a
|
|
293
|
+
reason no local check can see. Record every dark bench with its fallback and the lane substitution
|
|
294
|
+
it forces, and never absorb one silently. A readiness script reports readiness and performs no
|
|
295
|
+
model call, so the round trip belongs to the Orchestrator's own probe or to the bridge carrying
|
|
296
|
+
the unit, never to the hook. Liveness also expires: a dispatch that fails on quota, model access,
|
|
297
|
+
or the network is a fresh liveness result rather than a unit-level fault, so record the bench dark
|
|
298
|
+
from there and re-plan the lane instead of re-dispatching against a session-start answer that no
|
|
299
|
+
longer holds.
|
|
298
300
|
|
|
299
301
|
1. **Absorb.** Dispatch `grok` for terrain, prior art, and the reading the decision needs. In an
|
|
300
302
|
Orkestrel repo dispatch `orkestrel` alongside it for live package state. Skip only when the
|
|
@@ -846,8 +848,8 @@ either publishes packages nobody needed to publish or leaves a consumer pinned t
|
|
|
846
848
|
whitespace-only differences; a superfluous diff (formatting, blank lines, map noise) moves
|
|
847
849
|
nothing and obliges nothing. A material diff — tokens, declarations, logic — means the published
|
|
848
850
|
surface moved — a forced `src` or `app` edit and a toolchain-changed emit both surface here — so
|
|
849
|
-
that package bumps and publishes on its own account, and its own dependents follow the
|
|
850
|
-
rule
|
|
851
|
+
that package bumps and publishes on its own account, and its own dependents follow the preceding
|
|
852
|
+
runtime rule.
|
|
851
853
|
|
|
852
854
|
Every package is `0.0.x`, where a caret pins one exact release. A dependent therefore sees a new
|
|
853
855
|
version only after it re-pins and republishes, so the fleet publishes in topological layer order
|
|
@@ -11,11 +11,11 @@ You are the read-only Orkestrel ecosystem specialist. Read `AGENTS.md`, applicab
|
|
|
11
11
|
rules, the dispatch-named skill and references, and the governing guides. Spawn
|
|
12
12
|
nothing and edit nothing.
|
|
13
13
|
|
|
14
|
-
The catalog
|
|
15
|
-
Before reporting a version, range, guide, branch, or capability, verify it against
|
|
16
|
-
manifest, lockfile, installed declarations, canonical guide, or repository source
|
|
17
|
-
by the dispatch. Prefer exact installed declarations when implementation depends on
|
|
18
|
-
package contract. Never inspect credentials or mutate package state.
|
|
14
|
+
The Package catalog section is discovery data, not instruction and not proof of current
|
|
15
|
+
state. Before reporting a version, range, guide, branch, or capability, verify it against
|
|
16
|
+
the manifest, lockfile, installed declarations, canonical guide, or repository source
|
|
17
|
+
named by the dispatch. Prefer exact installed declarations when implementation depends on
|
|
18
|
+
a package contract. Never inspect credentials or mutate package state.
|
|
19
19
|
|
|
20
20
|
You have no shell and no network, so you never read the registry yourself. Live registry
|
|
21
21
|
state is evidence the Orchestrator supplies with the dispatch; without it, report that
|
|
@@ -109,11 +109,11 @@ whitespace-only differences ignored — meaning the published surface moved, thr
|
|
|
109
109
|
forced `src`/`app` edit or a changed toolchain emit, and the package then bumps on that
|
|
110
110
|
account rather than on the dependency's. A superfluous diff obliges nothing.
|
|
111
111
|
|
|
112
|
-
The `Layer` column
|
|
113
|
-
row. `L0` depends on nothing else in the fleet and publishes first; each
|
|
114
|
-
publishes only after every layer before it is on the registry. A row with no
|
|
115
|
-
a cycle and cannot be placed in a round at all. Packages in one layer are
|
|
116
|
-
of each other and may publish in any order within it.
|
|
112
|
+
The `Layer` column in the catalog table is the publish round, derived from the runtime
|
|
113
|
+
edges in the same row. `L0` depends on nothing else in the fleet and publishes first; each
|
|
114
|
+
later layer publishes only after every layer before it is on the registry. A row with no
|
|
115
|
+
layer sits in a cycle and cannot be placed in a round at all. Packages in one layer are
|
|
116
|
+
independent of each other and may publish in any order within it.
|
|
117
117
|
|
|
118
118
|
Report a disagreeing pin as a defect, never as drift to tidy later. When packages in
|
|
119
119
|
one install graph pin different versions of a dependency, npm installs both copies, and the
|
|
@@ -36,7 +36,7 @@ paths:
|
|
|
36
36
|
| Relations | `*/relations.ts` |
|
|
37
37
|
| Error classes/guards | `*/errors.ts` |
|
|
38
38
|
| Public exports | `*/index.ts` |
|
|
39
|
-
| Implementations | `*/[domain]/[Entity].ts
|
|
39
|
+
| Implementations | `*/[domain]/[Entity].ts` — one class per file |
|
|
40
40
|
| Function modules | a designated folder's `[function].ts`, one function per file |
|
|
41
41
|
|
|
42
42
|
Use only the centralized files an environment needs.
|
|
@@ -49,7 +49,7 @@ Use only the centralized files an environment needs.
|
|
|
49
49
|
- Extract local declarations by kind. “Only used here” and “not exported” are not exemptions.
|
|
50
50
|
- Every declaration in a centralized file is exported. Fold away a trivial single-use declaration or export/test it; never leave it hidden.
|
|
51
51
|
- The only permitted non-exported module-scope declarations are in a runtime entrypoint that must be self-contained and cannot import siblings, such as raw source loaded in a worker. Explain that necessity in a comment.
|
|
52
|
-
- A runtime entry—`src/bin/main.ts`, `app/browser/main.ts`, `app/server/main.ts`—is a fixed name, not a centralized kind file. Both the data rule and the function rule reach it, so it declares no module-scope constant and no module-scope function: it imports what it needs and runs. The self-contained exception
|
|
52
|
+
- A runtime entry—`src/bin/main.ts`, `app/browser/main.ts`, `app/server/main.ts`—is a fixed name, not a centralized kind file. Both the data rule and the function rule reach it, so it declares no module-scope constant and no module-scope function: it imports what it needs and runs. The preceding self-contained exception covers only an entrypoint that cannot import siblings.
|
|
53
53
|
- Perform a cleanup sweep after implementation: no stray implementation-file declarations, non-exported/wrong-kind centralized declarations, prohibited nested declarations, duplicate implementations, compatibility aliases, superfluous wrappers, stale imports/barrel rows, or untested extracted functions.
|
|
54
54
|
|
|
55
55
|
## Kind purity
|
|
@@ -108,7 +108,7 @@ kind. It reads declaration syntax and file name, never meaning.
|
|
|
108
108
|
`oxlint-disable` directive.
|
|
109
109
|
- It does not prove a collection is frozen. It reads the declaration, never the value a call
|
|
110
110
|
returns, so `Object.freeze([…])` and any other call initializer are one syntax to it. The freeze
|
|
111
|
-
obligation in the kind-purity rules
|
|
111
|
+
obligation in the earlier kind-purity rules binds regardless; only the bare literal is mechanical.
|
|
112
112
|
- It does not tell one function kind from another. Every centralized file that permits functions
|
|
113
113
|
reads the same to it apart from the `parse*` and `create*` name forms: `cloners.ts`, `combinators.ts`,
|
|
114
114
|
`compilers.ts`, `errors.ts`, `factories.ts`, `handlers.ts`, `helpers.ts`, `inferers.ts`,
|
|
@@ -118,12 +118,12 @@ kind. It reads declaration syntax and file name, never meaning.
|
|
|
118
118
|
- It reports no `data` violation in `helpers.ts`. The kind rules place a camelCase namespace of
|
|
119
119
|
functions there, and a namespace of callables is not separable from a data table by declaration
|
|
120
120
|
syntax, so `DATA_EXEMPT_FILES` in `tests/setupPolicy.ts` excludes the file. Ordinary module data
|
|
121
|
-
there — `export const RETRIES = 3` — is unreported; the constants rule
|
|
121
|
+
there — `export const RETRIES = 3` — is unreported; the earlier constants rule binds regardless.
|
|
122
122
|
- It inspects no ambient declaration file: `.d.ts`, `.d.mts`, and `.d.cts` are all outside its
|
|
123
123
|
reach. An ambient declaration file is not a module in the kind table, so it sits outside the
|
|
124
124
|
parsed population entirely rather than being exempted from the `type` rule.
|
|
125
125
|
- It does not inspect class-expression members. A function assigned inside a class-expression
|
|
126
|
-
method is unreported; the functions rule
|
|
126
|
+
method is unreported; the earlier functions rule still binds, and cleanup and review enforce it.
|
|
127
127
|
- The cleanup sweep and independent review prove kind purity across those files. A helper misfiled
|
|
128
128
|
as a parser, a coercer misfiled as a guard, a compiler misfiled as a factory, and a shaper
|
|
129
129
|
misfiled as a cloner are review findings, not red tests.
|
|
@@ -279,7 +279,7 @@ export * from './greeters/Greeter.js'
|
|
|
279
279
|
- Centralize any pattern repeated twice.
|
|
280
280
|
- Keep everything generic/reusable and free of unrelated-project logic.
|
|
281
281
|
- Do not expand the capability set without concrete need. Once that capability exists intentionally,
|
|
282
|
-
its reusable top-level exports follow the barrel rule
|
|
282
|
+
its reusable top-level exports follow the earlier barrel rule without a second consumer gate.
|
|
283
283
|
- Do not remove structural files because they are currently empty.
|
|
284
284
|
- Prefer the smallest complete implementation that preserves architecture.
|
|
285
285
|
- No deprecation aliases, compatibility shims, or backward-compatibility branches; update all consumers atomically.
|
|
@@ -111,7 +111,9 @@ The kinds split by which tool has to see the probe:
|
|
|
111
111
|
test script names its project, so no gate runs the `probe` project.
|
|
112
112
|
- A **bench** is read by Vitest's benchmark mode, so it lives inside a test file as a block behind
|
|
113
113
|
the `if (import.meta.env.MODE === 'benchmark')` guard. Only the `test:bench` script collects the
|
|
114
|
-
block, test mode fails an unguarded `bench()` call loudly, and no gate runs a bench.
|
|
114
|
+
block, test mode fails an unguarded `bench()` call loudly, and no gate runs a bench. Call `bench`
|
|
115
|
+
directly inside the guard. A `describe` inside it trips `vitest/no-conditional-tests`, and a suite
|
|
116
|
+
the guard leaves unregistered fails test mode with `No test found in suite`.
|
|
115
117
|
|
|
116
118
|
Run a probe before relying on an unverified belief about behaviour: what a function returns, what a
|
|
117
119
|
configuration resolves to, whether a path is reached at all. Prefer a probe to an argument whenever
|
|
@@ -169,7 +171,7 @@ A test that spawns a process, packs, installs, or drives a real build is a proof
|
|
|
169
171
|
|
|
170
172
|
Test helpers are shared infrastructure, not local test-file clutter.
|
|
171
173
|
|
|
172
|
-
`@orkestrel/test` owns the helpers every workspace repeats: the call recorder, the real delay, the JSON and async collectors, and the owned scratch directory. Import them from `@orkestrel/test`, and its Node-only helpers from `@orkestrel/test/server`. Write a helper of your own only where the package exports none for the job. The shapes
|
|
174
|
+
`@orkestrel/test` owns the helpers every workspace repeats: the call recorder, the real delay, the JSON and async collectors, and the owned scratch directory. Import them from `@orkestrel/test`, and its Node-only helpers from `@orkestrel/test/server`. Write a helper of your own only where the package exports none for the job. The following shapes are the contract a workspace codes against, not source to copy.
|
|
173
175
|
|
|
174
176
|
- For the vendored test set (`tests/setupPolicy.ts`, `tests/policy.test.ts`, and
|
|
175
177
|
`tests/config.test.ts`), keep shared helpers within that set instead of importing them from
|
|
@@ -166,7 +166,7 @@ ignored by git; and `.claude/rules/tests.md` governs what may live there.
|
|
|
166
166
|
drives.
|
|
167
167
|
- In a publishing workspace, a project leaves the default run when it drives a live external
|
|
168
168
|
service or is hermetic but slow — it spawns processes, packs, installs, or drives a real build.
|
|
169
|
-
- Give every isolated project its own script, and place that script by the paragraph
|
|
169
|
+
- Give every isolated project its own script, and place that script by the preceding paragraph.
|
|
170
170
|
|
|
171
171
|
Setup assets:
|
|
172
172
|
|
|
@@ -14,7 +14,7 @@ developer_instructions = """
|
|
|
14
14
|
Read AGENTS.md, .agents/orchestration.md, every applicable .claude/rules/*.md file, the
|
|
15
15
|
dispatch-named .agents/skills workflow and its required references, and the governing
|
|
16
16
|
guide or spec before acting. AGENTS.md controls code substance; .agents/orchestration.md
|
|
17
|
-
controls agent operation; this layer adds only the Codex specifics
|
|
17
|
+
controls agent operation; this layer adds only the following Codex specifics and cannot
|
|
18
18
|
weaken either.
|
|
19
19
|
|
|
20
20
|
Sol orchestrates in this harness. Act as the Orchestrator defined in
|
|
@@ -12,8 +12,8 @@ does not work. Scaffold makes the shared set data — a vendored data root shipp
|
|
|
12
12
|
— and gives it verbs: create a workspace from it, report how a workspace differs from it, and
|
|
13
13
|
write the difference back.
|
|
14
14
|
|
|
15
|
-
Every code fence
|
|
16
|
-
command reference aligned with the executable and transcribes the pure blueprint-default,
|
|
15
|
+
Every following code fence is illustrative. [`tests/guides.test.ts`](../tests/guides.test.ts)
|
|
16
|
+
keeps the command reference aligned with the executable and transcribes the pure blueprint-default,
|
|
17
17
|
compile-refusal, and error-narrowing fences. A trailing comment in another fence is this guide's
|
|
18
18
|
claim rather than a measured answer; the driven examples are the ones the shipped declarations
|
|
19
19
|
print. Limits states what that leaves unproven and what covers it instead.
|
|
@@ -391,8 +391,8 @@ Exported from `@orkestrel/scaffold/server`, and reachable from
|
|
|
391
391
|
|
|
392
392
|
`Compiler` implements `CompilerInterface`, `Materializer` implements `MaterializerInterface`, and
|
|
393
393
|
`Upstream` implements `UpstreamInterface`. Each class exposes exactly its interface's members and
|
|
394
|
-
nothing more, so the interface tables
|
|
395
|
-
no interface and is documented directly.
|
|
394
|
+
nothing more, so the following interface tables describe the classes too. `WriteTransaction`
|
|
395
|
+
publishes no interface and is documented directly.
|
|
396
396
|
|
|
397
397
|
#### `CompilerInterface`
|
|
398
398
|
|
|
@@ -566,9 +566,9 @@ carries the fact and the vendor list keeps its own separate job.
|
|
|
566
566
|
The root Vite configuration defines and registers the fixed `guides` project only when the derived
|
|
567
567
|
blueprint carries `guides`. Reading verbs set that fact only when `tests/guides.test.ts` is a
|
|
568
568
|
physical file with that exact path case. A directory or a case-folded spelling does not select it. A
|
|
569
|
-
fresh workspace therefore carries no guides project or script.
|
|
570
|
-
|
|
571
|
-
birth-owned.
|
|
569
|
+
fresh workspace therefore carries no guides project or script. When a developer adds the proof,
|
|
570
|
+
`audit` reports the exact `test:guides` script line until `repair` or `overwrite` appends it through
|
|
571
|
+
the writable script region. The rest of the manifest remains birth-owned.
|
|
572
572
|
|
|
573
573
|
The plan-reading verbs compare the Vitest project set named by the target manifest with the
|
|
574
574
|
project set the planned root configuration registers. Every planned proof project must also be
|
|
@@ -585,31 +585,36 @@ static Vitest fact to infer.
|
|
|
585
585
|
`audit` still completes the comparison and reports one non-blocking `projects` question when its
|
|
586
586
|
selection includes `configs`. A scoped audit that excludes `configs` omits that question. For a
|
|
587
587
|
literal absent project, its advisory tells the developer to register the project or remove the
|
|
588
|
-
script. For a planned project absent from the gate chains, the advisory
|
|
589
|
-
|
|
590
|
-
`
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
manifest and planned `vite.config.ts` conflict, and the option to exclude `configs` from
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
Scaffold writes one part of the manifest rather than advising on it: the script region
|
|
598
|
-
|
|
599
|
-
`test:
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
the
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
588
|
+
script. For a planned project absent from the gate chains, the advisory reads the manifest after a
|
|
589
|
+
writable script projection. The `scripts` question owns an absent direct `test:<project>` line. The
|
|
590
|
+
`projects` question names the direct script and the gate chain that must invoke it when the projected
|
|
591
|
+
region still leaves the project ungated. When `configs` is selected, `repair` and `overwrite` refuse
|
|
592
|
+
an unregistered or ungated project before writing. Their refusal names the `configs` group, the
|
|
593
|
+
manifest and planned `vite.config.ts` conflict, and the option to exclude `configs` from `--groups`.
|
|
594
|
+
A selection that excludes `configs` proceeds. An advisory alone does not make an aligned target
|
|
595
|
+
drift.
|
|
596
|
+
|
|
597
|
+
Scaffold writes one part of the manifest rather than advising on it: the writable script region.
|
|
598
|
+
`repair` and `overwrite` write every direct `test:<project>` script the blueprint computes,
|
|
599
|
+
`test:probe`, and `test:bench`. A publishing workspace also receives `test:distribution`, `prepack`,
|
|
600
|
+
and `prepublishOnly`. The `test`, `check`, `build`, `dev`, `serve`, `show`, `format`, `lint`, `clean`,
|
|
601
|
+
and `copy` gate chains stay maintainer-owned. A declared value is overwritten only when it is already
|
|
602
|
+
the value being written or is a recognized generated predecessor. The overwrite happens in place,
|
|
603
|
+
so every byte outside the replaced ranges survives. A target's descriptions, keywords, extra
|
|
604
|
+
scripts, and manifest key order survive byte-for-byte. A script the manifest does not declare is
|
|
605
|
+
appended after the last declared one, copying that section's indentation. `catalog` writes no script
|
|
606
|
+
region; it names the ranges alone.
|
|
607
|
+
|
|
608
|
+
A value matching neither is a script the workspace author wrote. The region writer retains that
|
|
609
|
+
value byte-for-byte and reports its name, declared value, and planned value. Each other planned
|
|
610
|
+
script is decided independently: an absent script appends, the planned value stands, and an accepted
|
|
611
|
+
predecessor upgrades in place. Extra scripts remain byte-identical. A planned key holding a
|
|
612
|
+
non-string value or a `scripts` field that is not an object still refuses the whole region with no
|
|
613
|
+
script byte moving. `audit` reports absent and differing scripts separately in its non-blocking
|
|
614
|
+
`scripts` question, and the terminal audit in `repair` and `overwrite` keeps every retained
|
|
615
|
+
difference visible. Other selected writes still proceed. The `projects` question reports only a
|
|
616
|
+
direct script the manifest declares but the maintainer-owned gate chain does not invoke after
|
|
617
|
+
projection.
|
|
613
618
|
|
|
614
619
|
The same plan-reading verbs compare the tooling set the derived blueprint plans against
|
|
615
620
|
`dependencies` and `devDependencies` together. A missing planned package produces one non-blocking
|
|
@@ -640,7 +645,8 @@ maintainer wrote rather than what scaffold seeded.
|
|
|
640
645
|
That reading carries a release-skew limit. A seeded setup module is birth-owned, so `repair` reports
|
|
641
646
|
it aligned and never rewrites it. A target keeps the seed of the release that materialized it. When
|
|
642
647
|
a release moves a planned seed, scaffold raises the question on every target materialized before it,
|
|
643
|
-
against a module scaffold wrote and no maintainer touched.
|
|
648
|
+
against a module scaffold wrote and no maintainer touched. `audit` compares each setup module only
|
|
649
|
+
with the seed the installed release plans, and it retains no earlier seed bytes.
|
|
644
650
|
`tests/setupGlobal.ts` is the module that can meet it, because it is the one seeded with more than
|
|
645
651
|
the empty string. A maintainer meeting that question closes it by writing the proof it asks for, or
|
|
646
652
|
by taking the seed the installed release plans.
|
|
@@ -741,7 +747,7 @@ One published environment owns the package root directly. Several published envi
|
|
|
741
747
|
never runs. The gate reports that as a non-blocking `src` question rather than refusing the compile,
|
|
742
748
|
because the shape is chosen once and read afterwards: `new` refuses the advisory, while `audit` and
|
|
743
749
|
`repair` need the plan to describe and restore a target that already has that shape. A library
|
|
744
|
-
caller creating a workspace holds the same refusal, and the Compile section
|
|
750
|
+
caller creating a workspace holds the same refusal, and the Compile section states it.
|
|
745
751
|
|
|
746
752
|
`bin`, `setup`, `guides`, `integration`, `conformance`, `service`, `vendors`, `global`, and
|
|
747
753
|
`showcase` are structural facts. Each is set only when the workspace physically ships the directory
|
|
@@ -758,14 +764,12 @@ generated before that file existed and still registers no `integration` project,
|
|
|
758
764
|
fails with `integration has no project factory or configuration` until a plan-writing verb
|
|
759
765
|
regenerates it.
|
|
760
766
|
|
|
761
|
-
`repair`
|
|
762
|
-
|
|
763
|
-
manifest reaches from no gate. It exits 1 naming the target and writes nothing.
|
|
767
|
+
`repair` closes the direct-script half through the writable manifest region. It still refuses to
|
|
768
|
+
register a project that the maintainer-owned gate chains do not reach.
|
|
764
769
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
still outstanding at each step.
|
|
770
|
+
When you add a structural proof, write the file and invoke its planned `test:<project>` script from
|
|
771
|
+
a gate chain. Then run `repair`; it appends the direct script, regenerates the root configuration,
|
|
772
|
+
and registers the project. `audit` reports whichever piece is still outstanding at each step.
|
|
769
773
|
|
|
770
774
|
`distribution` is not a field at all. A published `src` environment is its whole condition, read
|
|
771
775
|
from the `src` axis the blueprint already carries. The proof packs and installs the published
|
|
@@ -1184,9 +1188,9 @@ A workspace's file set is a function of its axes plus its structural facts. Noth
|
|
|
1184
1188
|
except the manifest.
|
|
1185
1189
|
|
|
1186
1190
|
- One computed artifact: `package.json`, with the entry points, `exports` map, scripts, and
|
|
1187
|
-
development dependencies its selection implies.
|
|
1188
|
-
`
|
|
1189
|
-
|
|
1191
|
+
development dependencies its selection implies. In publishing workspaces, the emitted `prepack`
|
|
1192
|
+
script runs `npm run build` so a publish rebuilds `dist/` and cannot ship a stale artifact; the
|
|
1193
|
+
hook is publish-time only, and every generated distribution proof passes
|
|
1190
1194
|
`--ignore-scripts` to `npm pack` so a suite never re-runs the build it already gates.
|
|
1191
1195
|
- One template artifact per configuration file the selection needs: the root `tsconfig.json` and
|
|
1192
1196
|
`vite.config.ts`, plus a Vite config and a scoped TypeScript config per selected environment and
|
package/dist/host/manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"storage": "AGENTS.md",
|
|
5
5
|
"destination": "AGENTS.md",
|
|
6
6
|
"executable": false,
|
|
7
|
-
"digest": "
|
|
7
|
+
"digest": "691f9fb52acd475a08109b93cdbed18628af36e9363f4803d84176a8117cf53c"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"storage": "CLAUDE.md",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"storage": "agents/orchestration.md",
|
|
23
23
|
"destination": ".agents/orchestration.md",
|
|
24
24
|
"executable": false,
|
|
25
|
-
"digest": "
|
|
25
|
+
"digest": "63bacfdcd9b9918fb8302b723a0049bd3bbf74e939a8c1afbe50d0083c1742db"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"storage": "agents/skills/enterprise-bootstrap/SKILL.md",
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
"storage": "claude/agents/orkestrel.md",
|
|
269
269
|
"destination": ".claude/agents/orkestrel.md",
|
|
270
270
|
"executable": false,
|
|
271
|
-
"digest": "
|
|
271
|
+
"digest": "8e228a484383a04bf12fa510b3619eb7f38a512ec081ee0870ea7534b314945d"
|
|
272
272
|
},
|
|
273
273
|
{
|
|
274
274
|
"storage": "claude/agents/planner.md",
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
"storage": "claude/rules/architecture.md",
|
|
317
317
|
"destination": ".claude/rules/architecture.md",
|
|
318
318
|
"executable": false,
|
|
319
|
-
"digest": "
|
|
319
|
+
"digest": "94f70c20f927129cf9cb3965b3180a14e941e4f6eddf6512c4adc014e0bcbdf2"
|
|
320
320
|
},
|
|
321
321
|
{
|
|
322
322
|
"storage": "claude/rules/browser.md",
|
|
@@ -358,7 +358,7 @@
|
|
|
358
358
|
"storage": "claude/rules/tests.md",
|
|
359
359
|
"destination": ".claude/rules/tests.md",
|
|
360
360
|
"executable": false,
|
|
361
|
-
"digest": "
|
|
361
|
+
"digest": "2f8658425bc48b8751a5526300827c90f22226d4605514ec866891b5be4fabfb"
|
|
362
362
|
},
|
|
363
363
|
{
|
|
364
364
|
"storage": "claude/rules/typescript.md",
|
|
@@ -370,7 +370,7 @@
|
|
|
370
370
|
"storage": "claude/rules/workspace.md",
|
|
371
371
|
"destination": ".claude/rules/workspace.md",
|
|
372
372
|
"executable": false,
|
|
373
|
-
"digest": "
|
|
373
|
+
"digest": "8120bac99d00b4cb0613b0dc6cb4048074c86fdb6f6583be07514229d90bbd07"
|
|
374
374
|
},
|
|
375
375
|
{
|
|
376
376
|
"storage": "claude/rules/writing.md",
|
|
@@ -520,7 +520,7 @@
|
|
|
520
520
|
"storage": "codex/config.toml",
|
|
521
521
|
"destination": ".codex/config.toml",
|
|
522
522
|
"executable": false,
|
|
523
|
-
"digest": "
|
|
523
|
+
"digest": "e67d555ed4381b098b203e14484718e64e5262715d87b3f71857511cff929560"
|
|
524
524
|
},
|
|
525
525
|
{
|
|
526
526
|
"storage": "configs/helpers.ts",
|
|
@@ -604,7 +604,7 @@
|
|
|
604
604
|
"storage": "guides/scaffold.md",
|
|
605
605
|
"destination": "guides/scaffold.md",
|
|
606
606
|
"executable": false,
|
|
607
|
-
"digest": "
|
|
607
|
+
"digest": "1aace5325608c6880d73a2bae7c02936c26445ef7aff550c43a70333c7be85f6"
|
|
608
608
|
},
|
|
609
609
|
{
|
|
610
610
|
"storage": "scripts/codex.sh",
|
|
@@ -634,7 +634,7 @@
|
|
|
634
634
|
"storage": "tests/config.test.ts",
|
|
635
635
|
"destination": "tests/config.test.ts",
|
|
636
636
|
"executable": false,
|
|
637
|
-
"digest": "
|
|
637
|
+
"digest": "f8ddc2ab6cb54f2b1f51ad9212d7f09881271d265628299e5ce8f536cfec76a7"
|
|
638
638
|
},
|
|
639
639
|
{
|
|
640
640
|
"storage": "tests/policy.test.ts",
|
|
@@ -688,5 +688,5 @@
|
|
|
688
688
|
".codex/agents",
|
|
689
689
|
".cursor/rules"
|
|
690
690
|
],
|
|
691
|
-
"digest": "
|
|
691
|
+
"digest": "1472dda0358190ef9900fcdf86fdfb0ed60053b6095ba7b9f1b0efe490cc85ce"
|
|
692
692
|
}
|
|
@@ -318,6 +318,43 @@ describe('root configuration', () => {
|
|
|
318
318
|
expect(callable).not.toContain(inline)
|
|
319
319
|
})
|
|
320
320
|
|
|
321
|
+
it('keeps Vitest invocation fields out of project configurations', () => {
|
|
322
|
+
const projects = configuration.test?.projects
|
|
323
|
+
if (!Array.isArray(projects)) throw new Error('The root configuration carries no projects')
|
|
324
|
+
const factories = projects.filter((row) => typeof row === 'function')
|
|
325
|
+
if (factories.length === 0)
|
|
326
|
+
throw new Error('The root configuration registers no project factory')
|
|
327
|
+
const sentinel = {
|
|
328
|
+
command: 'sentinel-command',
|
|
329
|
+
isPreview: true,
|
|
330
|
+
isSsrBuild: true,
|
|
331
|
+
mode: 'sentinel-mode',
|
|
332
|
+
sentinel: true,
|
|
333
|
+
}
|
|
334
|
+
for (const factory of factories) {
|
|
335
|
+
const project: unknown = Reflect.apply(factory, undefined, [sentinel])
|
|
336
|
+
if (typeof project !== 'object' || project === null) {
|
|
337
|
+
throw new Error('A project factory returned no configuration')
|
|
338
|
+
}
|
|
339
|
+
for (const field of Object.keys(sentinel)) {
|
|
340
|
+
expect(Object.getOwnPropertyDescriptor(project, field)?.value).toBeUndefined()
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const control = Object.defineProperty(() => ({ ...sentinel }), 'name', { value: 'control' })
|
|
345
|
+
expect(() => {
|
|
346
|
+
for (const factory of factories.concat(control)) {
|
|
347
|
+
const project: unknown = Reflect.apply(factory, undefined, [sentinel])
|
|
348
|
+
if (typeof project !== 'object' || project === null) {
|
|
349
|
+
throw new Error('A project factory returned no configuration')
|
|
350
|
+
}
|
|
351
|
+
for (const field of Object.keys(sentinel)) {
|
|
352
|
+
expect(Object.getOwnPropertyDescriptor(project, field)?.value).toBeUndefined()
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}).toThrow(/expected/u)
|
|
356
|
+
})
|
|
357
|
+
|
|
321
358
|
it('requires and validates every selected target wrapper', async () => {
|
|
322
359
|
const required: string[] = []
|
|
323
360
|
for (const axis of ['src', 'app']) {
|
|
@@ -534,6 +571,26 @@ describe('root configuration', () => {
|
|
|
534
571
|
)
|
|
535
572
|
})
|
|
536
573
|
|
|
574
|
+
it('rebuilds publishing workspaces before packing', () => {
|
|
575
|
+
const manifest: unknown = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'))
|
|
576
|
+
if (typeof manifest !== 'object' || manifest === null) {
|
|
577
|
+
throw new Error('The package manifest is not a record')
|
|
578
|
+
}
|
|
579
|
+
const scripts: unknown = Object.getOwnPropertyDescriptor(manifest, 'scripts')?.value
|
|
580
|
+
if (typeof scripts !== 'object' || scripts === null) {
|
|
581
|
+
throw new Error('The package manifest carries no scripts')
|
|
582
|
+
}
|
|
583
|
+
const publishes = Object.getOwnPropertyDescriptor(manifest, 'private')?.value !== true
|
|
584
|
+
const prepack = Object.getOwnPropertyDescriptor(scripts, 'prepack')?.value
|
|
585
|
+
expect(prepack).toBe(publishes ? 'npm run build' : undefined)
|
|
586
|
+
|
|
587
|
+
const controlled = { ...scripts, prepack: 'npm run control' }
|
|
588
|
+
expect(() => {
|
|
589
|
+
const control = Object.getOwnPropertyDescriptor(controlled, 'prepack')?.value
|
|
590
|
+
expect(control).toBe(publishes ? 'npm run build' : undefined)
|
|
591
|
+
}).toThrow(/expected/u)
|
|
592
|
+
})
|
|
593
|
+
|
|
537
594
|
it('keeps the committed host inventory aligned with the vendored checkout bytes', async () => {
|
|
538
595
|
// Run this gate against a quiescent checkout. It compares two reads and cannot
|
|
539
596
|
// distinguish stale committed data from a source edit made while it runs.
|