@orkestrel/scaffold 0.0.19 → 0.0.21
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 +15 -9
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/CLAUDE.md +51 -24
- package/dist/host/agents/skills/orkestrel-debrief/SKILL.md +69 -59
- package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +2 -2
- package/dist/host/agents/skills/orkestrel-debrief/references/instruction-audit.md +82 -0
- package/dist/host/claude/agents/application.md +34 -0
- package/dist/host/claude/agents/codex.md +7 -0
- package/dist/host/claude/agents/orkestrel.md +3 -3
- package/dist/host/claude/agents/researcher.md +31 -0
- package/dist/host/claude/agents/reviewer.md +5 -0
- package/dist/host/claude/agents/scout.md +25 -0
- package/dist/host/claude/rules/quality.md +10 -0
- package/dist/host/claude/rules/tests.md +10 -0
- package/dist/host/claude/skills/orkestrel-debrief/SKILL.md +1 -1
- package/dist/host/codex/agents/analyst.toml +5 -1
- package/dist/host/codex/agents/application.toml +23 -0
- package/dist/host/codex/agents/researcher.toml +22 -0
- package/dist/host/codex/agents/reviewer.toml +3 -1
- package/dist/host/codex/agents/scout.toml +18 -0
- package/dist/host/codex/config.toml +15 -6
- package/dist/host/guides/src/scaffold.md +120 -29
- package/dist/host/manifest.json +35 -0
- package/dist/host/tests/setupPolicy.ts +49 -11
- package/dist/src/core/index.cjs +1661 -856
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +84 -7
- package/dist/src/core/index.d.ts +84 -7
- package/dist/src/core/index.js +1656 -857
- package/dist/src/core/index.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name = "application"
|
|
2
|
+
description = "Terra executor for one fully specified app-layer unit — contracts, isolated config, entries, real host tests, guide parity; stops on any plan deviation."
|
|
3
|
+
model = "gpt-5.6-terra"
|
|
4
|
+
model_reasoning_effort = "low"
|
|
5
|
+
sandbox_mode = "workspace-write"
|
|
6
|
+
developer_instructions = """
|
|
7
|
+
The app-environment counterpart of builder. Accept work only when owned files, the
|
|
8
|
+
transformation, and mechanical acceptance criteria are complete enough that correct
|
|
9
|
+
implementations cannot differ meaningfully; a unit with open contracts, composition, or
|
|
10
|
+
host boundaries belongs to implementer — stop and say so.
|
|
11
|
+
|
|
12
|
+
Read AGENTS.md, .claude/rules/application.md, .claude/rules/workspace.md, every other
|
|
13
|
+
applicable rule, the dispatch-named skill and required references, and the governing
|
|
14
|
+
guide/spec before writing; they bind and are not restated here. Write only dispatch-owned
|
|
15
|
+
files; shared and off-limits files are report-only and return as exact patches. Validate
|
|
16
|
+
read-only and scoped to the owned app environment. Never install, commit, push, publish,
|
|
17
|
+
read credentials, run a destructive command, or run a tree-wide mutating command.
|
|
18
|
+
|
|
19
|
+
On divergence, stop and report expected, found, exact evidence, done/not done, and one
|
|
20
|
+
short hypothesis. Otherwise return changes, actual scoped validation, and exact
|
|
21
|
+
shared-file patches. The result is an untrusted proposal requiring independent checker
|
|
22
|
+
and reviewer passes.
|
|
23
|
+
"""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name = "researcher"
|
|
2
|
+
description = "Terra read-only primary-source research: external capabilities, upstream comparisons, installed dependency surfaces, capability/defect matrices with citations."
|
|
3
|
+
model = "gpt-5.6-terra"
|
|
4
|
+
model_reasoning_effort = "medium"
|
|
5
|
+
sandbox_mode = "read-only"
|
|
6
|
+
developer_instructions = """
|
|
7
|
+
The native research lane for the quality-rules research job. Gather and distill; never
|
|
8
|
+
design, implement, or decide. Read AGENTS.md and .claude/rules/quality.md first; they
|
|
9
|
+
bind and are not restated here.
|
|
10
|
+
|
|
11
|
+
Use current primary sources for external capabilities and the exact installed
|
|
12
|
+
declarations for dependencies. Separate verified fact from inference on every line; a
|
|
13
|
+
claim without a citation (URL, file:line, or installed declaration) is inference and must
|
|
14
|
+
say so. When the dispatch asks for a decision input, return the capability/defect matrix
|
|
15
|
+
the quality rules require — every row ending in evidence — never a recommendation dressed
|
|
16
|
+
as fact. Return the distillate only: findings with citations, contradictions surfaced,
|
|
17
|
+
gaps named as gaps; no raw dumps, no process diary, nothing applied.
|
|
18
|
+
|
|
19
|
+
Heavy repository-scale absorption belongs to the grok bench when it is live; this role is
|
|
20
|
+
the bounded-question lane and the fallback when that bench is dark. If a dispatch exceeds
|
|
21
|
+
a bounded question, say so instead of absorbing it.
|
|
22
|
+
"""
|
|
@@ -15,7 +15,9 @@ Verify that the `claude` CLI is available before dispatch. If it is absent or th
|
|
|
15
15
|
dispatch fails, return the failure immediately so the Sol main session can run the
|
|
16
16
|
design-audit pass itself and record that Opus was unavailable for this round.
|
|
17
17
|
Require PASS/FAIL, design-fit blockers with file:line evidence, nonblocking
|
|
18
|
-
advisories, and acceptance-criterion confirmations.
|
|
18
|
+
advisories, and acceptance-criterion confirmations. Require each design claim to be
|
|
19
|
+
tested by asking whether the shipped artifact still matches it, and anything not
|
|
20
|
+
settleable on subjective grounds to come back as an Analyst referral. For a rendered or externally
|
|
19
21
|
driven surface, require capture citations as primary evidence and the verdict shape
|
|
20
22
|
of the dispatch-named skill. Forbid edits, commands, orchestration, reconciliation,
|
|
21
23
|
and acceptance. Never invoke Fable, read credentials,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name = "scout"
|
|
2
|
+
description = "Terra read-only repository reconnaissance: locate files, symbols, seams, and structures; return file:line pointers and shape summaries, never judgment."
|
|
3
|
+
model = "gpt-5.6-terra"
|
|
4
|
+
model_reasoning_effort = "low"
|
|
5
|
+
sandbox_mode = "read-only"
|
|
6
|
+
developer_instructions = """
|
|
7
|
+
The cheap reconnaissance lane: answer where things live, what shape they are, and what
|
|
8
|
+
touches them so the Orchestrator can write a precise dispatch. Read AGENTS.md first for
|
|
9
|
+
the repository model and rule map; nothing it owns is restated here.
|
|
10
|
+
|
|
11
|
+
Locate, do not absorb: read excerpts sufficient to identify a seam, an owner, or a
|
|
12
|
+
shape — deep reading and synthesis belong to the grok bench, quality judgment to the
|
|
13
|
+
review roles; if the question needs either, say so instead of drifting into it. Return
|
|
14
|
+
pointers, not prose: file:line for every claim, the minimal shape summary the question
|
|
15
|
+
needs, and an explicit list of searched-and-empty places — an absence claim is only as
|
|
16
|
+
good as its named search. Never edit, never run commands, never speculate past the
|
|
17
|
+
evidence.
|
|
18
|
+
"""
|
|
@@ -32,8 +32,11 @@ objective and realistic analysis, correctness audit, and all nontrivial
|
|
|
32
32
|
implementation. Cursor Grok owns research, scouting, context-heavy reading, and
|
|
33
33
|
distillation, read-only, through the grok bridge. Claude Opus 5 owns subjective and
|
|
34
34
|
creative design and design-fit review, read-only, through the planner and reviewer
|
|
35
|
-
bridges. Terra drives bridges
|
|
36
|
-
|
|
35
|
+
bridges. Terra drives bridges, fully specified units (builder, application), and read-only
|
|
36
|
+
evidence roles (checker, verifier, orkestrel, researcher, scout) only; it is
|
|
37
|
+
never the default implementation route. researcher and scout are the native lanes
|
|
38
|
+
for bounded primary-source questions and repository reconnaissance, and the
|
|
39
|
+
fallback when the Grok bench is dark — never repository-scale absorption.
|
|
37
40
|
|
|
38
41
|
Work directly for trivial tasks. For non-trivial work: send the reading to grok; run
|
|
39
42
|
planner (Opus 5, subjective) and analyst (Sol, objective) on the
|
|
@@ -50,10 +53,16 @@ concurrently.
|
|
|
50
53
|
|
|
51
54
|
Every dispatch includes objective, context, AGENTS.md, applicable rules, governing
|
|
52
55
|
skill name/path and required references (or explicit none), guide/spec, owned and
|
|
53
|
-
off-limits files, permissions, exact output, deviation behavior,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
off-limits files, permissions, exact output, deviation behavior, declared unknowns
|
|
57
|
+
with how the unit reports them, the requirement that the executor spawns nothing,
|
|
58
|
+
and independently checkable acceptance criteria. Every brief is a file under tmp/
|
|
59
|
+
written before its unit launches, with the unit's report captured beside it; a
|
|
60
|
+
re-run amends the brief in a successor file rather than restating it; both are
|
|
61
|
+
swept at campaign acceptance, so anything that must outlive the campaign is
|
|
62
|
+
promoted into a durable artifact first. Writers stop when reality diverges; they do
|
|
63
|
+
not re-plan or debug beyond scope. After reconciling findings into briefs, every
|
|
64
|
+
retained finding names the brief item that carries it; a finding with no carrier is
|
|
65
|
+
a dropped finding.
|
|
57
66
|
|
|
58
67
|
A claim about a rendered or externally driven surface is evidenced by its capture
|
|
59
68
|
portfolio or a real foreign client driving it, never by source alone; the campaign
|
|
@@ -67,11 +67,41 @@ than aspirational:
|
|
|
67
67
|
- `app/browser` reaches server behavior only through shared `app/core` contracts and transports,
|
|
68
68
|
never through a server implementation import.
|
|
69
69
|
|
|
70
|
-
A generated `app/server` owns strict `
|
|
71
|
-
|
|
70
|
+
A generated `app/server` owns strict grouped `server.host`, `server.port`, and `server.timeout`
|
|
71
|
+
options plus the `APP_HOST`, `APP_PORT`, and `APP_START_TIMEOUT` environment boundaries. It
|
|
72
|
+
composes the installed router, server, and boundary/security/deadline middleware substrates around
|
|
73
|
+
a fresh `GET /health` dispatcher from `createApplicationDispatcher`, supports repeated start/stop
|
|
74
|
+
cycles and terminal destroy of both the server and its owned dispatcher, and writes exactly one
|
|
75
|
+
`[READY] <name> <url>` diagnostic after process-owned readiness. The process runner owns an emitter
|
|
76
|
+
whose `ApplicationServerRunnerEventMap` publishes `ready(url)` and `fail(error)`; initial
|
|
77
|
+
`ApplicationServerRunnerOptions.on` hooks run before the runner's own announcement and reporting
|
|
78
|
+
listeners; a synchronous fail hook sees an otherwise-unset `process.exitCode` as `undefined` before
|
|
79
|
+
the default reporter sets it to `1`. Concurrent stops join one substrate shutdown. In-process tests park on those events,
|
|
80
|
+
while child-process tests still observe the readiness line across the process boundary. Its exported
|
|
72
81
|
`reportApplicationServerError` handler writes only a stable configuration, lifecycle, or unknown
|
|
73
|
-
failure code; process-owned
|
|
74
|
-
other error context.
|
|
82
|
+
failure code; process-owned failures never serialize a rejected value, nested cause, stack,
|
|
83
|
+
secret, or other error context. `ApplicationState` extends middleware's `IdentifierState` and adds
|
|
84
|
+
only the connection fact. `ApplicationServer.url` is `undefined` until a real port is bound and
|
|
85
|
+
again after stop or destroy; the redundant `listening` projection is not part of the generated
|
|
86
|
+
interface. The runner narrows the post-start URL before writing `[READY]`, so it never announces a
|
|
87
|
+
stale or unbound address, and it stops the server as part of failing that narrowing rather than
|
|
88
|
+
leaving a bound listener without a shutdown owner. It also serializes every start and stop on one
|
|
89
|
+
lifecycle queue, so a stop waits for the startup it aborted to settle before closing the server,
|
|
90
|
+
and a restart issued during that shutdown is honoured after it rather than lost.
|
|
91
|
+
|
|
92
|
+
The health contract belongs to whichever layer both hosts can reach. While the server alone reads
|
|
93
|
+
it, `ApplicationRecord`, `APP_HEALTH_METHOD`, and `APP_HEALTH_PATH` stay declared in `app/server`.
|
|
94
|
+
The moment a blueprint declares `app/browser` beside `app/server` — a combination that already
|
|
95
|
+
requires `app/core` — those three declarations move to `app/core` and gain `APP_HEALTH_TIMEOUT`,
|
|
96
|
+
the `isApplicationRecord` guard, and `readApplicationHealth`. That one asynchronous read is the
|
|
97
|
+
whole browser/server boundary: it fetches the running server's health route, reads the body as
|
|
98
|
+
`unknown`, narrows it with the shared guard, and returns the shared `Application` identity or
|
|
99
|
+
`undefined` for an unreachable, slow, or off-contract answer. Nothing is duplicated by the move —
|
|
100
|
+
`app/server` imports the relocated contract from `@app/core`, and `app/browser` still never imports
|
|
101
|
+
a server module. The generated browser entry then mounts `mountBrowserApplication`, which performs
|
|
102
|
+
that single read before mounting and falls back to the locally configured identity when the
|
|
103
|
+
boundary yields `undefined`. A rejected mount reports the context-free
|
|
104
|
+
`[ERROR] Browser application failed`, the browser twin of that server-side discipline.
|
|
75
105
|
|
|
76
106
|
Every environment barrel is an export-star barrel: `index.ts` contains only `export * from './x.js'`
|
|
77
107
|
rows and nothing else. Named, default, namespace, and type-only barrel rows are absent by design,
|
|
@@ -416,7 +446,9 @@ From [`constants.ts`](../../src/core/constants.ts).
|
|
|
416
446
|
| `SCAFFOLD_RANGE` | const |
|
|
417
447
|
| `BASE_DEV_DEPENDENCIES` | const |
|
|
418
448
|
| `SOURCE_BROWSER_DEV_DEPENDENCIES` | const |
|
|
449
|
+
| `APP_DEV_DEPENDENCIES` | const |
|
|
419
450
|
| `APP_BROWSER_DEV_DEPENDENCIES` | const |
|
|
451
|
+
| `APP_SERVER_DEV_DEPENDENCIES` | const |
|
|
420
452
|
| `CHECKOUT_ACTION_SHA` | const |
|
|
421
453
|
| `SETUP_NODE_ACTION_SHA` | const |
|
|
422
454
|
| `COMPILER_ID` | const |
|
|
@@ -464,8 +496,11 @@ form. `HEX_PATTERN` requires whole lowercase byte pairs, and `SYNC_BASELINE_PATT
|
|
|
464
496
|
`MINIMUM_NODE_VERSION` is `22.12.0`, `DEFAULT_ENGINES` derives from it, and `DEFAULT_VERSION` is
|
|
465
497
|
`0.0.1`. `BASE_DEV_DEPENDENCIES` is the host-neutral tooling baseline every generated workspace
|
|
466
498
|
gets; `SOURCE_BROWSER_DEV_DEPENDENCIES` adds the real browser providers a published browser environment
|
|
467
|
-
needs
|
|
468
|
-
|
|
499
|
+
needs; `APP_DEV_DEPENDENCIES` is the baseline every private application environment gets;
|
|
500
|
+
`APP_BROWSER_DEV_DEPENDENCIES` adds the Vue toolchain and `@orkestrel/html` start-tag parser a
|
|
501
|
+
private browser application needs;
|
|
502
|
+
and `APP_SERVER_DEV_DEPENDENCIES` adds the emitter, middleware, router, and server packages a private
|
|
503
|
+
server application needs. Vite is minor-pinned at `~8.2.0`: the generated boundary consumes the reviewed
|
|
469
504
|
8.2 `CSSOptions`, `preprocessCSS`, and `isCSSRequest` surface, while the selected
|
|
470
505
|
`css.transformer` / `lightningcss` path is experimental and must not float into an unreviewed minor.
|
|
471
506
|
`SCAFFOLD_RANGE` is the range generated workspaces pin this package at.
|
|
@@ -788,6 +823,8 @@ From [`helpers.ts`](../../src/core/helpers.ts).
|
|
|
788
823
|
| `pascalCase` | function |
|
|
789
824
|
| `escapeHtmlText` | function |
|
|
790
825
|
| `serializeTypeScriptString` | function |
|
|
826
|
+
| `hasApplicationBoundary` | function |
|
|
827
|
+
| `hasApplicationShowcase` | function |
|
|
791
828
|
| `blueprintToMembers` | function |
|
|
792
829
|
| `catalogNames` | function |
|
|
793
830
|
| `alignTable` | function |
|
|
@@ -824,6 +861,7 @@ From [`helpers.ts`](../../src/core/helpers.ts).
|
|
|
824
861
|
| `renderArray` | function |
|
|
825
862
|
| `renderObject` | function |
|
|
826
863
|
| `renderValue` | function |
|
|
864
|
+
| `renderStringArray` | function |
|
|
827
865
|
| `formatJson` | function |
|
|
828
866
|
| `pinPlan` | function |
|
|
829
867
|
|
|
@@ -836,7 +874,9 @@ guard. `blueprint` fills the defaults: `version` and `engines` from their consta
|
|
|
836
874
|
derives the entity name from a lowercase-hyphen package name, and `blueprintToMembers` derives the
|
|
837
875
|
declared public `Member[]` — a full entity, options type, interface, and factory per published
|
|
838
876
|
environment, plus the exact declaration inventory each selected application environment
|
|
839
|
-
contributes.
|
|
877
|
+
contributes. `hasApplicationBoundary` recognizes exactly app/core + app/browser + app/server,
|
|
878
|
+
while `hasApplicationShowcase` requires showcase intent beside app/browser; plan assembly, tests,
|
|
879
|
+
guides, and member inventory share those predicates.
|
|
840
880
|
|
|
841
881
|
`escapeHtmlText` and `serializeTypeScriptString` are the two escaping leaves used when a
|
|
842
882
|
caller-supplied name reaches generated HTML or generated TypeScript source; the latter preserves
|
|
@@ -888,7 +928,12 @@ id is already registered: an identical plan is idempotent, while a distinct payl
|
|
|
888
928
|
`formatJson` and its leaves — `renderValue`,
|
|
889
929
|
`renderArray`, `renderObject`, `computeColumnWidth`, and `fitsPrintWidth` — emit JSON that matches the fleet
|
|
890
930
|
formatter byte for byte, collapsing a short array onto one line and breaking a long one, so
|
|
891
|
-
computed configuration JSON is format-stable by construction.
|
|
931
|
+
computed configuration JSON is format-stable by construction. `renderStringArray` applies the same
|
|
932
|
+
inline-or-broken width rule to single-quoted TypeScript string-array literals — with a trailing
|
|
933
|
+
comma on every broken line, matching `oxfmt`'s `trailingComma: "all"` for non-JSON files — so
|
|
934
|
+
generated TypeScript configuration is format-stable too. It serializes every string element through
|
|
935
|
+
`serializeTypeScriptString`, so quotes, backslashes, controls, and line separators remain inert in
|
|
936
|
+
both layouts.
|
|
892
937
|
|
|
893
938
|
### Helpers — server
|
|
894
939
|
|
|
@@ -1049,6 +1094,7 @@ From [`compilers.ts`](../../src/core/compilers.ts).
|
|
|
1049
1094
|
| `renderViteTest` | function |
|
|
1050
1095
|
| `viteHeader` | function |
|
|
1051
1096
|
| `policyViteProject` | function |
|
|
1097
|
+
| `configViteProject` | function |
|
|
1052
1098
|
| `guidesViteProject` | function |
|
|
1053
1099
|
| `binViteProject` | function |
|
|
1054
1100
|
| `integrationViteProject` | function |
|
|
@@ -1136,7 +1182,7 @@ formatter's 100-column fixed point: a complete registration-array line, includin
|
|
|
1136
1182
|
its trailing comma, stays collapsed when it fits and expands one entry per line otherwise.
|
|
1137
1183
|
`viteProjectRegistrations` is the one registration derivation every root shape consumes: it derives
|
|
1138
1184
|
the selected source and application projects from the canonical environment order, then appends
|
|
1139
|
-
`policy`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
|
|
1185
|
+
`policy`, `config`, `guides`, and the optional `srcBin`, `integration`, and `service` projects.
|
|
1140
1186
|
`viteProjectDefinitions` renders the standalone proof and structural-fact definitions in that same
|
|
1141
1187
|
order with one blank line between declarations. Both consume `ViteFacts`, so each optional project
|
|
1142
1188
|
is controlled only by its matching `bin`, `integration`, or `service` blueprint fact; the same
|
|
@@ -1149,8 +1195,9 @@ the root `srcCore` factory and its wrapper stay host-independent even when the w
|
|
|
1149
1195
|
browser target. `binTsconfig` emits the executable declaration scope; `rootViteConfig`,
|
|
1150
1196
|
`singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for a library-only,
|
|
1151
1197
|
single non-core `src` environment, and application-bearing workspace respectively; and
|
|
1152
|
-
`policyViteProject`, `guidesViteProject`, `integrationViteProject`, and
|
|
1153
|
-
the standalone Node proof projects, with `binViteProject` the single
|
|
1198
|
+
`policyViteProject`, `configViteProject`, `guidesViteProject`, `integrationViteProject`, and
|
|
1199
|
+
`serviceViteProject` emit the standalone Node proof projects, with `binViteProject` the single
|
|
1200
|
+
executable-project emitter. A
|
|
1154
1201
|
proof project is structurally derived from the directory holding its tests and never wraps a source
|
|
1155
1202
|
or application environment project. The guides project therefore uses only `tests/setup.ts`, never
|
|
1156
1203
|
`setupServer.ts`, `setupBrowser.ts`, or `setupService.ts`; and its `tests/src/**/*.test.ts` and
|
|
@@ -1540,13 +1587,13 @@ a fixed, interleaved order so aggregates sit immediately before their per-enviro
|
|
|
1540
1587
|
- `format`, `format:check`, `lint:check`
|
|
1541
1588
|
- `test`, then `test:src` and its per-environment scopes, the optional `test:integration`,
|
|
1542
1589
|
`test:equivalence`, and `test:service` proofs, `test:app` and its per-environment scopes, then
|
|
1543
|
-
`test:policy` and `test:guides`
|
|
1590
|
+
`test:policy`, `test:config`, and `test:guides`
|
|
1544
1591
|
- `build`, then `build:src` and its per-environment targets, `build:app` and its runtime targets, and
|
|
1545
1592
|
`build:host` for a bin workspace
|
|
1546
1593
|
- `dev` when a browser application is selected; `serve` and `serve:build` when a server application
|
|
1547
1594
|
is selected
|
|
1548
1595
|
- `showcase`, `build:showcase`, and `show` only when the physical showcase wrapper is present;
|
|
1549
|
-
`show` builds
|
|
1596
|
+
`show` formats, then builds, then copies `dist/showcase/index.html` to `demo/showcase.html`
|
|
1550
1597
|
- `prepublishOnly` chaining `format:check → lint:check → check → build → test`, followed by
|
|
1551
1598
|
`test:integration` when the integration axis is selected
|
|
1552
1599
|
|
|
@@ -1560,8 +1607,9 @@ only where `bin` and `integration` are both set:
|
|
|
1560
1607
|
| `test:equivalence` | no | no | no |
|
|
1561
1608
|
| `test:service` | no | never | after `scripts/service.sh` |
|
|
1562
1609
|
|
|
1563
|
-
No proof joins the default chain: `npm test` runs the source, application, policy,
|
|
1564
|
-
projects, and nothing there needs a build artifact or a foreign process.
|
|
1610
|
+
No opt-in proof joins the default chain: `npm test` runs the source, application, policy,
|
|
1611
|
+
configuration, and guide projects, and nothing there needs a build artifact or a foreign process.
|
|
1612
|
+
Publication is the one
|
|
1565
1613
|
asymmetry — `prepublishOnly` appends `test:integration`, because a package about to be published
|
|
1566
1614
|
should prove itself against its own built output, while `test:service` is never in that chain.
|
|
1567
1615
|
Neither default testing nor publication starts or requires a foreign process.
|
|
@@ -1633,10 +1681,16 @@ comments, text, raw blocks, attributes, adjacent tokens, casing, and user-author
|
|
|
1633
1681
|
byte-stable. The trusted preparation hook owns the final pre-parse phase; inline proxy code is
|
|
1634
1682
|
restored before module analysis, and the first normal post-parse hook restores the original HTML
|
|
1635
1683
|
spelling. The browser entry begins with a generated, byte-stable security prologue: the doctype,
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1684
|
+
head opening, and `Content-Security-Policy` meta markup, ordering, and indentation are exact. The
|
|
1685
|
+
opening `html` start tag is parsed by `@orkestrel/html`'s fail-closed `parseStartTag` boundary,
|
|
1686
|
+
so ASCII case and well-formed attributes such as `lang`, `data-bs-theme`, and `data-bs-core`
|
|
1687
|
+
may vary without weakening the position of the following head and policy. A malformed, incomplete,
|
|
1688
|
+
duplicate-attribute, wrong-name, or syntactically slashed root still fails closed. Preparation owns
|
|
1689
|
+
that positional check while the document is still generated bytes; the final trusted post-hook
|
|
1690
|
+
checks only that the exact
|
|
1691
|
+
policy survived because Vite may legitimately inject into the head. CRLF and LF files are both
|
|
1692
|
+
accepted. Vite's
|
|
1693
|
+
`%ENV%` HTML substitution is rejected
|
|
1640
1694
|
before parsing because Vite performs that expansion after every plugin pre-hook, where it could
|
|
1641
1695
|
otherwise create a late control attribute. The guard walks the exact left-to-right `%(\S+?)%`
|
|
1642
1696
|
tokens Vite recognizes instead of performing a substring search, and each preparation plugin owns
|
|
@@ -1685,15 +1739,31 @@ still rejects public directories, browser asset inlining, and output path overri
|
|
|
1685
1739
|
post-factory composition as defense in depth; that narrow check is not a general extension seam.
|
|
1686
1740
|
|
|
1687
1741
|
When the showcase fact is present, the generated root also exports closed
|
|
1688
|
-
`appShowcase(...config: never[])`; both factories reject every argument at runtime
|
|
1689
|
-
|
|
1742
|
+
`appShowcase(...config: never[])`; both factories reject every argument at runtime. The
|
|
1743
|
+
ordinary factory retains its strict
|
|
1690
1744
|
`script-src 'self'` policy, external asset auditing, and `dist/app/browser` output. The showcase
|
|
1691
|
-
factory
|
|
1745
|
+
factory is a standalone configuration with `base: './'`, unlimited asset inlining, and
|
|
1746
|
+
`dist/showcase` output. It applies `viteSingleFile` with
|
|
1692
1747
|
`removeViteModuleLoader: true` and `useRecommendedBuildConfig: true`, uses Oxc and Lightning CSS
|
|
1693
|
-
minification for an `esnext` build without source maps or module preload, and inserts a
|
|
1694
|
-
`build-id`
|
|
1695
|
-
|
|
1696
|
-
|
|
1748
|
+
minification for an `esnext` build without source maps or module preload, and inserts a SHA-256
|
|
1749
|
+
`build-id` derived from the secured, fully inlined document. An unchanged document therefore keeps
|
|
1750
|
+
the same id, while any changed byte changes it. The showcase development CSP keeps scripts
|
|
1751
|
+
same-origin and permits Vue's injected inline styles. Its built CSP swaps that script permission to
|
|
1752
|
+
inline and admits only inline styles plus data images and fonts, while both policies retain
|
|
1753
|
+
`default-src 'none'`, `script-src-attr 'none'`, `object-src 'none'`, and `base-uri 'none'`.
|
|
1754
|
+
|
|
1755
|
+
The showcase fact also emits its own entry pair, `app/browser/showcase.html` and
|
|
1756
|
+
`app/browser/showcase.ts`, beside the application's `index.html` and `main.ts`. Both HTML entries
|
|
1757
|
+
open with a generated security prologue: the application carries the ordinary strict policy and the
|
|
1758
|
+
showcase carries its development policy. The boundary plugins select and validate the matching
|
|
1759
|
+
prologue; the showcase build alone swaps in the self-contained policy before hashing and renames its
|
|
1760
|
+
single HTML output to `index.html`, which is what `show` copies to `demo/showcase.html`. The showcase entry
|
|
1761
|
+
mounts `mountShowcaseApplication`, and `app/browser/seeders.ts` exports exactly one seeder,
|
|
1762
|
+
`seedApplication`, returning a frozen identity of the same shape the shipped root view receives.
|
|
1763
|
+
The two mount factories differ in the seed expression alone. Both explicitly pass
|
|
1764
|
+
`{ name: seed.name }` to the same `createBrowserApplication` root: the showcase seed comes from
|
|
1765
|
+
`seedApplication()`, while the shipped application seed comes from `readApplicationHealth` with
|
|
1766
|
+
the configured identity as its fallback.
|
|
1697
1767
|
|
|
1698
1768
|
The browser development server applies the same trust boundary before Vite's internal middleware.
|
|
1699
1769
|
Its explicit filesystem allowlist contains only browser/core source roots, browser tests, their
|
|
@@ -1756,12 +1826,26 @@ it is not a general-purpose source analyzer. Generated workspaces receive the sa
|
|
|
1756
1826
|
module as a host-origin file and run it as a dedicated Node-only `policy` test project over
|
|
1757
1827
|
`tests/policy.test.ts`.
|
|
1758
1828
|
|
|
1829
|
+
**The configuration suite.** Policy reads source, the `config` project exercises the root
|
|
1830
|
+
configuration, and integration builds for real. Every generated workspace therefore receives a
|
|
1831
|
+
universal Node-only
|
|
1832
|
+
`config` project over `tests/config/**/*.test.ts`. Its base cases execute the root module's physical
|
|
1833
|
+
workspace containment and environment-direction helpers; conditional cases exercise output
|
|
1834
|
+
containment when the workspace builds, managed/system browser discovery when a browser environment
|
|
1835
|
+
exists, and the HTML/CSP boundary only for an application browser. Those cases import the generated
|
|
1836
|
+
root `vite.config.ts` itself, so a failure is repaired in the generator rather than patched into a
|
|
1837
|
+
consumer. The generated-consumer integration matrix remains the fidelity boundary for real builds;
|
|
1838
|
+
the configuration suite supplies deterministic edge coverage without duplicating build orchestration.
|
|
1839
|
+
When scaffold changes a generated configuration invariant, an existing consumer's `vite.config.ts`
|
|
1840
|
+
is intentionally reported stale until that consumer accepts the regenerated configuration and its
|
|
1841
|
+
matching config test.
|
|
1842
|
+
|
|
1759
1843
|
**Real browser capability.** Browser test projects are gated on one centralized discovery chain:
|
|
1760
1844
|
Playwright's pinned Chromium executable first, then a managed Chromium alias or cached revision,
|
|
1761
1845
|
then stable system Chrome, then stable system Edge. Managed candidates must be executable regular
|
|
1762
1846
|
files. System channels are selected only when their executable exists at Playwright's standard
|
|
1763
1847
|
Linux, macOS, or Windows installation location; custom installations are not guessed. The generated
|
|
1764
|
-
|
|
1848
|
+
configuration test consumes the same discovery helpers and accepts either an executable managed path or the
|
|
1765
1849
|
stable `chrome` / `msedge` channel, so it does not maintain a second heuristic.
|
|
1766
1850
|
|
|
1767
1851
|
A browser suite runs when any one of those real browser capabilities is available and is skipped
|
|
@@ -1900,7 +1984,10 @@ renderer behind the table and blockquote work; the template engine behind every
|
|
|
1900
1984
|
artifact; and, consumed only at the executable boundary, the terminal prompt toolkit and the console
|
|
1901
1985
|
reporter. The core face uses the first four and stays pure; the server face adds only `node:*`
|
|
1902
1986
|
builtins. Development dependencies are the shared tooling baseline plus the guide-parity toolkit
|
|
1903
|
-
that drives [`parity.test.ts`](../../tests/guides/src/parity.test.ts)
|
|
1987
|
+
that drives [`parity.test.ts`](../../tests/guides/src/parity.test.ts) and `@orkestrel/html`,
|
|
1988
|
+
which this package's real emitted-configuration tests execute. Generated manifests keep that HTML
|
|
1989
|
+
dependency scoped to `app/browser`; source-only, `app/core`, and `app/server` workspaces do not
|
|
1990
|
+
receive it. The engines floor is Node
|
|
1904
1991
|
`>=22.12.0`, and the build emits ES and CJS for both library faces plus an ES executable.
|
|
1905
1992
|
|
|
1906
1993
|
## Patterns
|
|
@@ -2245,6 +2332,7 @@ import {
|
|
|
2245
2332
|
appViteConfig,
|
|
2246
2333
|
applicationViteConfig,
|
|
2247
2334
|
binViteProject,
|
|
2335
|
+
configViteProject,
|
|
2248
2336
|
coreTsconfig,
|
|
2249
2337
|
coreViteConfig,
|
|
2250
2338
|
guidesViteProject,
|
|
@@ -2276,13 +2364,14 @@ coreViteConfig()
|
|
|
2276
2364
|
srcViteConfig('browser')
|
|
2277
2365
|
appViteConfig('server')
|
|
2278
2366
|
policyViteProject()
|
|
2367
|
+
configViteProject()
|
|
2279
2368
|
guidesViteProject()
|
|
2280
2369
|
binViteProject()
|
|
2281
2370
|
integrationViteProject({ bin: true, integration: true, global: true })
|
|
2282
2371
|
serviceViteProject()
|
|
2283
2372
|
viteProjectDefinitions({ integration: true }).includes('export const integration =') // true
|
|
2284
2373
|
viteProjectRegistrations(['core'], [], { integration: true }).map(({ project }) => project)
|
|
2285
|
-
// ['srcCore', 'policy', 'guides', 'integration']
|
|
2374
|
+
// ['srcCore', 'policy', 'config', 'guides', 'integration']
|
|
2286
2375
|
|
|
2287
2376
|
rootViteConfig(['core', 'server'], { bin: true })
|
|
2288
2377
|
singleSrcViteConfig('server').includes('srcServer') // true
|
|
@@ -2576,6 +2665,8 @@ isMissingPathError(caught) // true only for an ENOENT error
|
|
|
2576
2665
|
ids, the batch-overload semantics, and all-or-nothing list removal.
|
|
2577
2666
|
- [`tests/src/core/policy.test.ts`](../../tests/src/core/policy.test.ts) — the repository coding-law
|
|
2578
2667
|
policy module against this workspace and against deliberately hostile fixtures.
|
|
2668
|
+
- [`tests/config/vite.test.ts`](../../tests/config/vite.test.ts) — the executable root Vite
|
|
2669
|
+
invariants for workspace, environment, and output containment.
|
|
2579
2670
|
- [`tests/src/server/helpers.test.ts`](../../tests/src/server/helpers.test.ts) — containment,
|
|
2580
2671
|
digests, host staging, hydration, derivation, prune scanning, and the local catalog.
|
|
2581
2672
|
- [`tests/src/server/validators.test.ts`](../../tests/src/server/validators.test.ts) — the portable
|
package/dist/host/manifest.json
CHANGED
|
@@ -75,6 +75,11 @@
|
|
|
75
75
|
"destination": ".agents/skills/orkestrel-debrief/references/field-testing.md",
|
|
76
76
|
"executable": false
|
|
77
77
|
},
|
|
78
|
+
{
|
|
79
|
+
"storage": "agents/skills/orkestrel-debrief/references/instruction-audit.md",
|
|
80
|
+
"destination": ".agents/skills/orkestrel-debrief/references/instruction-audit.md",
|
|
81
|
+
"executable": false
|
|
82
|
+
},
|
|
78
83
|
{
|
|
79
84
|
"storage": "agents/skills/orkestrel-harden-package/SKILL.md",
|
|
80
85
|
"destination": ".agents/skills/orkestrel-harden-package/SKILL.md",
|
|
@@ -120,6 +125,11 @@
|
|
|
120
125
|
"destination": ".agents/skills/orkestrel-polish-surface/references/capture-harness.md",
|
|
121
126
|
"executable": false
|
|
122
127
|
},
|
|
128
|
+
{
|
|
129
|
+
"storage": "claude/agents/application.md",
|
|
130
|
+
"destination": ".claude/agents/application.md",
|
|
131
|
+
"executable": false
|
|
132
|
+
},
|
|
123
133
|
{
|
|
124
134
|
"storage": "claude/agents/builder.md",
|
|
125
135
|
"destination": ".claude/agents/builder.md",
|
|
@@ -155,11 +165,21 @@
|
|
|
155
165
|
"destination": ".claude/agents/planner.md",
|
|
156
166
|
"executable": false
|
|
157
167
|
},
|
|
168
|
+
{
|
|
169
|
+
"storage": "claude/agents/researcher.md",
|
|
170
|
+
"destination": ".claude/agents/researcher.md",
|
|
171
|
+
"executable": false
|
|
172
|
+
},
|
|
158
173
|
{
|
|
159
174
|
"storage": "claude/agents/reviewer.md",
|
|
160
175
|
"destination": ".claude/agents/reviewer.md",
|
|
161
176
|
"executable": false
|
|
162
177
|
},
|
|
178
|
+
{
|
|
179
|
+
"storage": "claude/agents/scout.md",
|
|
180
|
+
"destination": ".claude/agents/scout.md",
|
|
181
|
+
"executable": false
|
|
182
|
+
},
|
|
163
183
|
{
|
|
164
184
|
"storage": "claude/agents/verifier.md",
|
|
165
185
|
"destination": ".claude/agents/verifier.md",
|
|
@@ -260,6 +280,11 @@
|
|
|
260
280
|
"destination": ".codex/agents/analyst.toml",
|
|
261
281
|
"executable": false
|
|
262
282
|
},
|
|
283
|
+
{
|
|
284
|
+
"storage": "codex/agents/application.toml",
|
|
285
|
+
"destination": ".codex/agents/application.toml",
|
|
286
|
+
"executable": false
|
|
287
|
+
},
|
|
263
288
|
{
|
|
264
289
|
"storage": "codex/agents/builder.toml",
|
|
265
290
|
"destination": ".codex/agents/builder.toml",
|
|
@@ -295,11 +320,21 @@
|
|
|
295
320
|
"destination": ".codex/agents/planner.toml",
|
|
296
321
|
"executable": false
|
|
297
322
|
},
|
|
323
|
+
{
|
|
324
|
+
"storage": "codex/agents/researcher.toml",
|
|
325
|
+
"destination": ".codex/agents/researcher.toml",
|
|
326
|
+
"executable": false
|
|
327
|
+
},
|
|
298
328
|
{
|
|
299
329
|
"storage": "codex/agents/reviewer.toml",
|
|
300
330
|
"destination": ".codex/agents/reviewer.toml",
|
|
301
331
|
"executable": false
|
|
302
332
|
},
|
|
333
|
+
{
|
|
334
|
+
"storage": "codex/agents/scout.toml",
|
|
335
|
+
"destination": ".codex/agents/scout.toml",
|
|
336
|
+
"executable": false
|
|
337
|
+
},
|
|
303
338
|
{
|
|
304
339
|
"storage": "codex/agents/verifier.toml",
|
|
305
340
|
"destination": ".codex/agents/verifier.toml",
|
|
@@ -18,6 +18,7 @@ export const CENTRAL_SOURCE_FILES: readonly string[] = Object.freeze([
|
|
|
18
18
|
'middlewares.ts',
|
|
19
19
|
'parsers.ts',
|
|
20
20
|
'relations.ts',
|
|
21
|
+
'routes.ts',
|
|
21
22
|
'schemas.ts',
|
|
22
23
|
'seeders.ts',
|
|
23
24
|
'shapers.ts',
|
|
@@ -39,6 +40,7 @@ export const FUNCTION_SOURCE_FILES: readonly string[] = Object.freeze([
|
|
|
39
40
|
'middlewares.ts',
|
|
40
41
|
'parsers.ts',
|
|
41
42
|
'relations.ts',
|
|
43
|
+
'routes.ts',
|
|
42
44
|
'schemas.ts',
|
|
43
45
|
'seeders.ts',
|
|
44
46
|
'shapers.ts',
|
|
@@ -51,6 +53,7 @@ export const DATA_SOURCE_FILES: readonly string[] = Object.freeze([
|
|
|
51
53
|
'constants.ts',
|
|
52
54
|
'contracts.ts',
|
|
53
55
|
'relations.ts',
|
|
56
|
+
'routes.ts',
|
|
54
57
|
'schemas.ts',
|
|
55
58
|
'shapers.ts',
|
|
56
59
|
'templates.ts',
|
|
@@ -90,6 +93,22 @@ export const WORKER_SCOPE_VALUE_GLOBALS: readonly string[] = Object.freeze([
|
|
|
90
93
|
'removeEventListener',
|
|
91
94
|
])
|
|
92
95
|
|
|
96
|
+
/** Source extensions inspected by the repository coding-law sweep. */
|
|
97
|
+
export const CODING_SOURCE_EXTENSIONS: readonly string[] = Object.freeze([
|
|
98
|
+
'cjs',
|
|
99
|
+
'cts',
|
|
100
|
+
'js',
|
|
101
|
+
'jsx',
|
|
102
|
+
'mjs',
|
|
103
|
+
'mts',
|
|
104
|
+
'ts',
|
|
105
|
+
'tsx',
|
|
106
|
+
'vue',
|
|
107
|
+
])
|
|
108
|
+
|
|
109
|
+
/** Production-source glob derived from the complete inspected extension vocabulary. */
|
|
110
|
+
export const CODING_SOURCE_GLOB = `{app,src}/**/*.{${CODING_SOURCE_EXTENSIONS.join(',')}}`
|
|
111
|
+
|
|
93
112
|
/** Virtual source text used while binding one policy-inspected module. */
|
|
94
113
|
export const POLICY_SOURCE_TEXTS: Map<string, string> = new Map()
|
|
95
114
|
|
|
@@ -109,6 +128,17 @@ export function normalizePolicyPath(path: string): string {
|
|
|
109
128
|
return path.replaceAll('\\', '/').replace(/\/+/gu, '/')
|
|
110
129
|
}
|
|
111
130
|
|
|
131
|
+
/** Whether a path belongs to the production-source coding-law corpus. */
|
|
132
|
+
export function isCodingSourcePath(path: string): boolean {
|
|
133
|
+
const normalized = normalizePolicyPath(path)
|
|
134
|
+
const extension = normalized.split('.').pop()
|
|
135
|
+
return (
|
|
136
|
+
(normalized.startsWith('app/') || normalized.startsWith('src/')) &&
|
|
137
|
+
extension !== undefined &&
|
|
138
|
+
CODING_SOURCE_EXTENSIONS.includes(extension)
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
112
142
|
/** Whether a declaration carries an explicit export modifier. */
|
|
113
143
|
export function hasExportModifier(node: ts.Node): boolean {
|
|
114
144
|
return (
|
|
@@ -416,6 +446,22 @@ export function inspectVueCodingLaw(
|
|
|
416
446
|
return violations
|
|
417
447
|
}
|
|
418
448
|
|
|
449
|
+
/** Inspect one production source through the shared coding-law route. */
|
|
450
|
+
export function inspectCodingSource(
|
|
451
|
+
path: string,
|
|
452
|
+
content: string,
|
|
453
|
+
vueScripts?: VueScriptExtractorInterface,
|
|
454
|
+
): readonly string[] {
|
|
455
|
+
const normalizedPath = normalizePolicyPath(path)
|
|
456
|
+
if (!normalizedPath.endsWith('.vue')) return inspectCodingLaw(normalizedPath, content)
|
|
457
|
+
const violations: string[] = []
|
|
458
|
+
if (!normalizedPath.startsWith('app/browser/')) {
|
|
459
|
+
violations.push(`${normalizedPath} Vue components belong in app/browser`)
|
|
460
|
+
}
|
|
461
|
+
violations.push(...inspectVueCodingLaw(normalizedPath, vueScripts?.(normalizedPath, content)))
|
|
462
|
+
return violations
|
|
463
|
+
}
|
|
464
|
+
|
|
419
465
|
/** Add syntax-wide coding-law violations while traversing one source tree. */
|
|
420
466
|
export function inspectCodingNode(
|
|
421
467
|
path: string,
|
|
@@ -627,25 +673,17 @@ export function inspectCodingLaw(path: string, content: string): readonly string
|
|
|
627
673
|
return violations
|
|
628
674
|
}
|
|
629
675
|
|
|
630
|
-
/** Inspect every production
|
|
676
|
+
/** Inspect every production source under one workspace. */
|
|
631
677
|
export function inspectCodingWorkspace(
|
|
632
678
|
root: string,
|
|
633
679
|
vueScripts?: VueScriptExtractorInterface,
|
|
634
680
|
): readonly string[] {
|
|
635
681
|
const violations: string[] = []
|
|
636
|
-
for (const path of globSync(
|
|
682
|
+
for (const path of globSync(CODING_SOURCE_GLOB, {
|
|
637
683
|
cwd: root,
|
|
638
684
|
})) {
|
|
639
685
|
const content = readFileSync(join(root, path), 'utf8')
|
|
640
|
-
|
|
641
|
-
if (path.endsWith('.vue') && !normalizedPath.startsWith('app/browser/')) {
|
|
642
|
-
violations.push(`${normalizedPath} Vue components belong in app/browser`)
|
|
643
|
-
}
|
|
644
|
-
violations.push(
|
|
645
|
-
...(path.endsWith('.vue')
|
|
646
|
-
? inspectVueCodingLaw(normalizedPath, vueScripts?.(normalizedPath, content))
|
|
647
|
-
: inspectCodingLaw(normalizedPath, content)),
|
|
648
|
-
)
|
|
686
|
+
violations.push(...inspectCodingSource(path, content, vueScripts))
|
|
649
687
|
}
|
|
650
688
|
return violations
|
|
651
689
|
}
|