@orkestrel/scaffold 0.0.3 → 0.0.5
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/host/AGENTS.md +1 -1
- package/dist/host/CLAUDE.md +108 -33
- package/dist/host/claude/agents/application.md +0 -2
- package/dist/host/claude/agents/builder.md +1 -3
- package/dist/host/claude/agents/checker.md +0 -1
- package/dist/host/claude/agents/codex.md +89 -19
- package/dist/host/claude/agents/grok.md +27 -7
- package/dist/host/claude/agents/implementer.md +40 -0
- package/dist/host/claude/agents/orkestrel.md +0 -1
- package/dist/host/claude/agents/planner.md +0 -1
- package/dist/host/claude/agents/reviewer.md +1 -2
- package/dist/host/claude/agents/verifier.md +0 -1
- package/dist/host/claude/rules/architecture.md +2 -1
- package/dist/host/claude/settings.json +1 -5
- package/dist/host/codex/agents/implementer.toml +2 -2
- package/dist/host/codex/agents/opus.toml +25 -0
- package/dist/host/codex/config.toml +5 -3
- package/dist/host/cursor/mcp.json +12 -0
- package/dist/host/dotfiles/mcp.json +8 -0
- package/dist/host/guides/src/scaffold.md +39 -5
- package/dist/host/manifest.json +21 -0
- package/dist/host/tests/setupPolicy.ts +47 -11
- package/dist/src/core/index.cjs +168 -93
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +58 -13
- package/dist/src/core/index.d.ts +58 -13
- package/dist/src/core/index.js +168 -94
- package/dist/src/core/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -37,12 +37,14 @@ Work directly for trivial tasks. For non-trivial work: send the reading to grok;
|
|
|
37
37
|
planner (Opus 5, subjective) and analyst (Sol, objective) on the
|
|
38
38
|
SAME design brief in parallel without showing either the other's answer, then
|
|
39
39
|
reconcile them into one plan; plan bounded units with disjoint ownership; route each
|
|
40
|
-
nontrivial unit to implementer (Sol)
|
|
40
|
+
nontrivial unit to implementer (Sol) or the opus implementation bridge (Opus 5) —
|
|
41
|
+
whichever engine fits the unit — reserving builder/application for fully
|
|
41
42
|
specified taste-free mechanics; integrate
|
|
42
43
|
shared files serially; obtain an independent reviewer (Opus 5) design audit and an
|
|
43
44
|
independent analyst (Sol) correctness audit plus a checker conformance pass; then
|
|
44
|
-
run one verifier. Parallelize only independent units. Writing agents
|
|
45
|
-
disjoint owned files and never run tree-wide mutating commands
|
|
45
|
+
run one verifier. Parallelize only independent units. Writing agents run serially in the
|
|
46
|
+
main checkout with disjoint owned files and never run tree-wide mutating commands
|
|
47
|
+
concurrently.
|
|
46
48
|
|
|
47
49
|
Every dispatch includes objective, context, AGENTS.md, applicable rules, governing
|
|
48
50
|
skill name/path and required references (or explicit none), guide/spec, owned and
|
|
@@ -133,6 +133,7 @@ From [`types.ts`](../../src/core/types.ts).
|
|
|
133
133
|
| `BuildFormat` | type |
|
|
134
134
|
| `SrcDefinition` | interface |
|
|
135
135
|
| `AppDefinition` | interface |
|
|
136
|
+
| `ViteMachinery` | interface |
|
|
136
137
|
| `Origin` | type |
|
|
137
138
|
| `Group` | type |
|
|
138
139
|
| `Category` | type |
|
|
@@ -183,6 +184,12 @@ is `'INVALID' | 'BLOCKED' | 'DESTROYED' | 'TARGET' | 'WRITE' | 'FETCH'`.
|
|
|
183
184
|
environment contributes, its test-project label, and — on the `src` axis — its `exports` subpath
|
|
184
185
|
and build formats, or — on the `app` axis — its optional runtime entry.
|
|
185
186
|
|
|
187
|
+
`ViteMachinery` names the three host-specific pipelines a workspace's generated `vite.config.ts` may
|
|
188
|
+
carry: `browser` for the CSS pipeline and the Playwright-backed browser test project, `vue` for the
|
|
189
|
+
single-file-component, HTML, and development-server machinery an application browser environment
|
|
190
|
+
needs, and `output` for build-output containment. It never selects a boundary guarantee — those ship
|
|
191
|
+
in every shape, as the compilers section sets out.
|
|
192
|
+
|
|
186
193
|
`Blueprint` is the closed input spec:
|
|
187
194
|
|
|
188
195
|
```ts
|
|
@@ -946,6 +953,7 @@ From [`compilers.ts`](../../src/core/compilers.ts).
|
|
|
946
953
|
| `devDependenciesFor` | function |
|
|
947
954
|
| `packageManifest` | function |
|
|
948
955
|
| `rootTsconfig` | function |
|
|
956
|
+
| `viteMachinery` | function |
|
|
949
957
|
| `viteHeader` | function |
|
|
950
958
|
| `policyViteProject` | function |
|
|
951
959
|
| `singleSrcViteConfig` | function |
|
|
@@ -987,10 +995,33 @@ optional metadata, and engines.
|
|
|
987
995
|
`rootTsconfig` emits the root compiler options and one path alias per declared environment;
|
|
988
996
|
`coreTsconfig`, `srcTsconfig`, and `appTsconfig` emit the scoped configurations that remove the
|
|
989
997
|
wrong host's globals from each environment. `viteHeader` renders the shared header — the alias block
|
|
990
|
-
derived from the tsconfig paths, plus the environment-boundary plugin
|
|
991
|
-
|
|
992
|
-
`
|
|
993
|
-
|
|
998
|
+
derived from the tsconfig paths, plus the environment-boundary plugin — and `viteMachinery` is the
|
|
999
|
+
one place the header's axes are derived, read by `rootViteConfig`, `singleSrcViteConfig`,
|
|
1000
|
+
`applicationViteConfig`, and `configArtifacts` alike so no caller can invent a fourth answer.
|
|
1001
|
+
|
|
1002
|
+
**The boundary guarantees do not vary by blueprint.** Every generated `vite.config.ts` — a
|
|
1003
|
+
`core`-only library, an application of `app/core` alone, or the full six-environment workspace —
|
|
1004
|
+
emits `environmentBoundary`, its `resolveId` / `load` / `buildEnd` walks, the module-graph AST audit
|
|
1005
|
+
(`environmentAssetSources`, `parseSync`, `Visitor`), and stylesheet rejection (`isStylesheetPath`
|
|
1006
|
+
plus its `environmentPathError` / `environmentSourceError` clauses). Those enforce owner-independent
|
|
1007
|
+
laws: core stays host-independent whatever else the workspace declares, a server module never
|
|
1008
|
+
imports a stylesheet, and a `@vite-ignore` dynamic import — which `resolveId` never sees and the
|
|
1009
|
+
module graph never records — has no other enforcement point. Only host-specific pipelines vary,
|
|
1010
|
+
along the three `ViteMachinery` axes:
|
|
1011
|
+
|
|
1012
|
+
| Machinery | Emitted when |
|
|
1013
|
+
| ----------------------------------------------------------------- | ------------------------------------ |
|
|
1014
|
+
| CSS pipeline (`ENVIRONMENT_CSS`, `preprocessCSS`, `isCSSRequest`) | a `src` or `app` browser environment |
|
|
1015
|
+
| Playwright provider and `hasChromium` | a `src` or `app` browser environment |
|
|
1016
|
+
| Vue plugin, HTML boundary, browser development server | an `app` browser environment |
|
|
1017
|
+
| Output containment (`outputBoundary`, `enforceOutputPath`) | anything the workspace builds |
|
|
1018
|
+
|
|
1019
|
+
An application of `app/core` alone is the sole shape that builds nothing, so it is the sole shape
|
|
1020
|
+
without output containment — and it still carries every boundary guarantee above.
|
|
1021
|
+
|
|
1022
|
+
`coreViteConfig`, `srcViteConfig`, and `appViteConfig` emit the thin per-target wrappers;
|
|
1023
|
+
`rootViteConfig`, `singleSrcViteConfig`, and `applicationViteConfig` emit the root configuration for
|
|
1024
|
+
a library-only, single non-core `src` environment, and application-bearing workspace respectively;
|
|
994
1025
|
`policyViteProject` emits the dedicated Node-only repository-policy test project.
|
|
995
1026
|
|
|
996
1027
|
`configArtifacts`, `sourceArtifacts`, `applicationArtifacts`, `testArtifacts`, and `guideArtifacts`
|
|
@@ -1924,6 +1955,7 @@ import {
|
|
|
1924
1955
|
srcTsconfig,
|
|
1925
1956
|
srcViteConfig,
|
|
1926
1957
|
viteHeader,
|
|
1958
|
+
viteMachinery,
|
|
1927
1959
|
} from '@orkestrel/scaffold'
|
|
1928
1960
|
|
|
1929
1961
|
rootTsconfig(['core'], ['core', 'server'])
|
|
@@ -1931,7 +1963,9 @@ coreTsconfig()
|
|
|
1931
1963
|
srcTsconfig('server')
|
|
1932
1964
|
appTsconfig('browser', true)
|
|
1933
1965
|
|
|
1934
|
-
|
|
1966
|
+
viteMachinery(['core']) // { browser: false, vue: false, output: true }
|
|
1967
|
+
viteMachinery([], ['core', 'browser']) // { browser: true, vue: true, output: true }
|
|
1968
|
+
viteHeader(viteMachinery([], ['core', 'browser'])) // the shared header, with browser and Vue support
|
|
1935
1969
|
coreViteConfig()
|
|
1936
1970
|
srcViteConfig('browser')
|
|
1937
1971
|
appViteConfig('server')
|
package/dist/host/manifest.json
CHANGED
|
@@ -90,6 +90,11 @@
|
|
|
90
90
|
"destination": ".claude/agents/grok.md",
|
|
91
91
|
"executable": false
|
|
92
92
|
},
|
|
93
|
+
{
|
|
94
|
+
"storage": "claude/agents/implementer.md",
|
|
95
|
+
"destination": ".claude/agents/implementer.md",
|
|
96
|
+
"executable": false
|
|
97
|
+
},
|
|
93
98
|
{
|
|
94
99
|
"storage": "claude/agents/orkestrel.md",
|
|
95
100
|
"destination": ".claude/agents/orkestrel.md",
|
|
@@ -215,6 +220,11 @@
|
|
|
215
220
|
"destination": ".codex/agents/implementer.toml",
|
|
216
221
|
"executable": false
|
|
217
222
|
},
|
|
223
|
+
{
|
|
224
|
+
"storage": "codex/agents/opus.toml",
|
|
225
|
+
"destination": ".codex/agents/opus.toml",
|
|
226
|
+
"executable": false
|
|
227
|
+
},
|
|
218
228
|
{
|
|
219
229
|
"storage": "codex/agents/orkestrel.toml",
|
|
220
230
|
"destination": ".codex/agents/orkestrel.toml",
|
|
@@ -240,6 +250,11 @@
|
|
|
240
250
|
"destination": ".codex/config.toml",
|
|
241
251
|
"executable": false
|
|
242
252
|
},
|
|
253
|
+
{
|
|
254
|
+
"storage": "cursor/mcp.json",
|
|
255
|
+
"destination": ".cursor/mcp.json",
|
|
256
|
+
"executable": false
|
|
257
|
+
},
|
|
243
258
|
{
|
|
244
259
|
"storage": "dotfiles/editorconfig",
|
|
245
260
|
"destination": ".editorconfig",
|
|
@@ -255,6 +270,11 @@
|
|
|
255
270
|
"destination": ".gitignore",
|
|
256
271
|
"executable": false
|
|
257
272
|
},
|
|
273
|
+
{
|
|
274
|
+
"storage": "dotfiles/mcp.json",
|
|
275
|
+
"destination": ".mcp.json",
|
|
276
|
+
"executable": false
|
|
277
|
+
},
|
|
258
278
|
{
|
|
259
279
|
"storage": "dotfiles/oxfmtrc.json",
|
|
260
280
|
"destination": ".oxfmtrc.json",
|
|
@@ -347,6 +367,7 @@
|
|
|
347
367
|
".claude/skills/orkestrel-harden-package",
|
|
348
368
|
".codex",
|
|
349
369
|
".codex/agents",
|
|
370
|
+
".cursor",
|
|
350
371
|
"guides",
|
|
351
372
|
"guides/src",
|
|
352
373
|
"scripts",
|
|
@@ -13,6 +13,7 @@ export const CENTRAL_SOURCE_FILES: readonly string[] = Object.freeze([
|
|
|
13
13
|
'factories.ts',
|
|
14
14
|
'helpers.ts',
|
|
15
15
|
'handlers.ts',
|
|
16
|
+
'inferers.ts',
|
|
16
17
|
'middlewares.ts',
|
|
17
18
|
'parsers.ts',
|
|
18
19
|
'relations.ts',
|
|
@@ -33,6 +34,7 @@ export const FUNCTION_SOURCE_FILES: readonly string[] = Object.freeze([
|
|
|
33
34
|
'factories.ts',
|
|
34
35
|
'handlers.ts',
|
|
35
36
|
'helpers.ts',
|
|
37
|
+
'inferers.ts',
|
|
36
38
|
'middlewares.ts',
|
|
37
39
|
'parsers.ts',
|
|
38
40
|
'relations.ts',
|
|
@@ -100,6 +102,23 @@ export function isDirectCallback(node: ts.ArrowFunction | ts.FunctionExpression)
|
|
|
100
102
|
)
|
|
101
103
|
}
|
|
102
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Whether an arrow/function expression is returned directly as a factory or combinator result.
|
|
107
|
+
*
|
|
108
|
+
* @param node - The function expression to inspect
|
|
109
|
+
* @returns `true` when the node is a direct return value, including one parenthesized layer
|
|
110
|
+
*/
|
|
111
|
+
export function isDirectReturn(node: ts.ArrowFunction | ts.FunctionExpression): boolean {
|
|
112
|
+
const parent = node.parent
|
|
113
|
+
if (ts.isReturnStatement(parent)) return true
|
|
114
|
+
if (ts.isArrowFunction(parent) && parent.body === node) return true
|
|
115
|
+
if (!ts.isParenthesizedExpression(parent)) return false
|
|
116
|
+
const container = parent.parent
|
|
117
|
+
return (
|
|
118
|
+
ts.isReturnStatement(container) || (ts.isArrowFunction(container) && container.body === parent)
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
103
122
|
/** Whether a function expression is assigned by one module-scope variable declaration. */
|
|
104
123
|
export function isModuleFunction(node: ts.ArrowFunction | ts.FunctionExpression): boolean {
|
|
105
124
|
const declaration = node.parent
|
|
@@ -113,6 +132,18 @@ export function isModuleFunction(node: ts.ArrowFunction | ts.FunctionExpression)
|
|
|
113
132
|
)
|
|
114
133
|
}
|
|
115
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Format a syntax node's source position as a one-based line and character.
|
|
137
|
+
*
|
|
138
|
+
* @param node - The syntax node whose starting position to format
|
|
139
|
+
* @returns The node's one-based `line:character` position
|
|
140
|
+
*/
|
|
141
|
+
export function formatPolicyPosition(node: ts.Node): string {
|
|
142
|
+
const source = node.getSourceFile()
|
|
143
|
+
const position = source.getLineAndCharacterOfPosition(node.getStart())
|
|
144
|
+
return `${String(position.line + 1)}:${String(position.character + 1)}`
|
|
145
|
+
}
|
|
146
|
+
|
|
116
147
|
/** Whether a property signature belongs to a centralized interface or type alias contract. */
|
|
117
148
|
export function isContractProperty(node: ts.PropertySignature): boolean {
|
|
118
149
|
let parent: ts.Node = node.parent
|
|
@@ -162,10 +193,10 @@ export function inspectCodingNode(path: string, node: ts.Node, violations: strin
|
|
|
162
193
|
ts.isTypeAssertionExpression(node) ||
|
|
163
194
|
ts.isNonNullExpression(node)
|
|
164
195
|
) {
|
|
165
|
-
violations.push(`${path}:${node
|
|
196
|
+
violations.push(`${path}:${formatPolicyPosition(node)} forbids type/non-null assertions`)
|
|
166
197
|
}
|
|
167
198
|
if (node.kind === ts.SyntaxKind.AnyKeyword) {
|
|
168
|
-
violations.push(`${path}:${node
|
|
199
|
+
violations.push(`${path}:${formatPolicyPosition(node)} forbids any`)
|
|
169
200
|
}
|
|
170
201
|
if (
|
|
171
202
|
(ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
|
|
@@ -173,14 +204,14 @@ export function inspectCodingNode(path: string, node: ts.Node, violations: strin
|
|
|
173
204
|
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
174
205
|
isUnsupportedModuleSpecifier(node.moduleSpecifier.text)
|
|
175
206
|
) {
|
|
176
|
-
violations.push(`${path}:${node
|
|
207
|
+
violations.push(`${path}:${formatPolicyPosition(node)} forbids non-Node URL module specifiers`)
|
|
177
208
|
}
|
|
178
209
|
if (
|
|
179
210
|
ts.isPropertySignature(node) &&
|
|
180
211
|
isContractProperty(node) &&
|
|
181
212
|
!hasModifier(node, ts.SyntaxKind.ReadonlyKeyword)
|
|
182
213
|
) {
|
|
183
|
-
violations.push(`${path}:${node
|
|
214
|
+
violations.push(`${path}:${formatPolicyPosition(node)} requires readonly contract properties`)
|
|
184
215
|
}
|
|
185
216
|
if (
|
|
186
217
|
ts.isCallExpression(node) &&
|
|
@@ -188,7 +219,7 @@ export function inspectCodingNode(path: string, node: ts.Node, violations: strin
|
|
|
188
219
|
(node.arguments.length !== 1 || !node.arguments.every(ts.isStringLiteral))
|
|
189
220
|
) {
|
|
190
221
|
violations.push(
|
|
191
|
-
`${path}:${node
|
|
222
|
+
`${path}:${formatPolicyPosition(node)} requires dynamic imports to use string literals so import policy remains enforceable`,
|
|
192
223
|
)
|
|
193
224
|
}
|
|
194
225
|
if (
|
|
@@ -198,17 +229,18 @@ export function inspectCodingNode(path: string, node: ts.Node, violations: strin
|
|
|
198
229
|
node.arguments.every(ts.isStringLiteral) &&
|
|
199
230
|
isUnsupportedModuleSpecifier(node.arguments[0]?.text ?? '')
|
|
200
231
|
) {
|
|
201
|
-
violations.push(`${path}:${node
|
|
232
|
+
violations.push(`${path}:${formatPolicyPosition(node)} forbids non-Node URL module specifiers`)
|
|
202
233
|
}
|
|
203
234
|
if (ts.isFunctionDeclaration(node) && !ts.isSourceFile(node.parent)) {
|
|
204
|
-
violations.push(`${path}:${node
|
|
235
|
+
violations.push(`${path}:${formatPolicyPosition(node)} forbids nested function declarations`)
|
|
205
236
|
}
|
|
206
237
|
if (
|
|
207
238
|
(ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
208
239
|
!isDirectCallback(node) &&
|
|
240
|
+
!isDirectReturn(node) &&
|
|
209
241
|
!isModuleFunction(node)
|
|
210
242
|
) {
|
|
211
|
-
violations.push(`${path}:${node
|
|
243
|
+
violations.push(`${path}:${formatPolicyPosition(node)} forbids hidden function assignments`)
|
|
212
244
|
}
|
|
213
245
|
ts.forEachChild(node, (child) => inspectCodingNode(path, child, violations))
|
|
214
246
|
}
|
|
@@ -290,14 +322,18 @@ export function inspectCodingLaw(path: string, content: string): readonly string
|
|
|
290
322
|
!ts.isIdentifier(declaration.name) ||
|
|
291
323
|
!/^[A-Z][A-Z0-9_]*$/u.test(declaration.name.text)
|
|
292
324
|
) {
|
|
293
|
-
violations.push(
|
|
325
|
+
violations.push(
|
|
326
|
+
`${path}:${formatPolicyPosition(declaration)} requires UPPER_SNAKE_CASE constants`,
|
|
327
|
+
)
|
|
294
328
|
}
|
|
295
329
|
if (
|
|
296
330
|
declaration.initializer !== undefined &&
|
|
297
331
|
(ts.isArrayLiteralExpression(declaration.initializer) ||
|
|
298
332
|
ts.isObjectLiteralExpression(declaration.initializer))
|
|
299
333
|
) {
|
|
300
|
-
violations.push(
|
|
334
|
+
violations.push(
|
|
335
|
+
`${path}:${formatPolicyPosition(declaration)} freezes collection constants`,
|
|
336
|
+
)
|
|
301
337
|
}
|
|
302
338
|
}
|
|
303
339
|
}
|
|
@@ -321,7 +357,7 @@ export function inspectCodingLaw(path: string, content: string): readonly string
|
|
|
321
357
|
}
|
|
322
358
|
for (const member of classes[0]?.members ?? []) {
|
|
323
359
|
if (hasModifier(member, ts.SyntaxKind.PrivateKeyword)) {
|
|
324
|
-
violations.push(`${path}:${member
|
|
360
|
+
violations.push(`${path}:${formatPolicyPosition(member)} uses runtime # privacy`)
|
|
325
361
|
}
|
|
326
362
|
}
|
|
327
363
|
}
|