@orkestrel/scaffold 0.0.81 → 0.0.83
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/agents/skills/orkestrel-publish/scripts/wave.js +14 -3
- package/dist/bin/main.js +295 -13
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +5 -3
- package/dist/host/agents/orchestration.md +1 -0
- package/dist/host/agents/skills/orkestrel-harden/references/centralization.md +2 -2
- package/dist/host/agents/skills/orkestrel-journey/SKILL.md +43 -39
- package/dist/host/agents/skills/orkestrel-journey/references/captures.md +3 -3
- package/dist/host/agents/skills/orkestrel-journey/references/decide.md +10 -9
- package/dist/host/agents/skills/orkestrel-journey/references/layer.md +5 -5
- package/dist/host/agents/skills/orkestrel-journey/references/recorded.md +77 -0
- package/dist/host/agents/skills/orkestrel-journey/references/statechart.md +3 -3
- package/dist/host/agents/skills/orkestrel-journey/references/styles.md +9 -9
- package/dist/host/agents/skills/orkestrel-publish/references/wave.md +4 -0
- package/dist/host/agents/skills/orkestrel-publish/scripts/wave.ts +22 -4
- package/dist/host/claude/agents/orkestrel.md +10 -10
- package/dist/host/claude/rules/application.md +20 -6
- package/dist/host/claude/rules/architecture.md +2 -2
- package/dist/host/claude/rules/browser.md +9 -0
- package/dist/host/claude/rules/documentation.md +2 -1
- package/dist/host/claude/rules/quality.md +5 -0
- package/dist/host/claude/rules/styles.md +35 -12
- package/dist/host/claude/rules/tests.md +15 -10
- package/dist/host/claude/rules/workspace.md +128 -98
- package/dist/host/claude/skills/orkestrel-journey/SKILL.md +1 -1
- package/dist/host/configs/helpers.ts +157 -9
- package/dist/host/configs/policy.ts +64 -61
- package/dist/host/dotfiles/oxlintrc.json +132 -16
- package/dist/host/dotfiles/prettierignore +1 -1
- package/dist/host/guides/README.md +9 -5
- package/dist/host/guides/guide.md +4 -1
- package/dist/host/guides/scaffold.md +482 -115
- package/dist/host/manifest.json +38 -32
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/host/tests/config.test.ts +996 -39
- package/dist/host/tests/policy.test.ts +11 -0
- package/dist/host/tests/setupPolicy.ts +396 -22
- package/dist/src/core/index.cjs +1289 -164
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +313 -35
- package/dist/src/core/index.d.ts +313 -35
- package/dist/src/core/index.js +1268 -165
- package/dist/src/core/index.js.map +1 -1
- package/package.json +7 -6
|
@@ -20,6 +20,7 @@ export interface PolicyExpression extends PolicyNode {
|
|
|
20
20
|
readonly callee?: PolicyExpression
|
|
21
21
|
readonly argument?: PolicyExpression | null
|
|
22
22
|
readonly arguments?: readonly PolicyExpression[]
|
|
23
|
+
readonly elements?: ReadonlyArray<PolicyExpression | null>
|
|
23
24
|
readonly body?: PolicyExpression | readonly PolicyExpression[]
|
|
24
25
|
readonly quasis?: readonly PolicyExpression[]
|
|
25
26
|
readonly expressions?: readonly PolicyExpression[]
|
|
@@ -514,39 +515,65 @@ export function isPolicyDeclaredFunction(node: PolicyExpression): boolean {
|
|
|
514
515
|
return node.type === 'FunctionDeclaration' || node.type === 'TSDeclareFunction'
|
|
515
516
|
}
|
|
516
517
|
|
|
517
|
-
/**
|
|
518
|
-
export function isPolicyAnonymous(node: PolicyExpression): boolean {
|
|
519
|
-
return node.type === 'ArrowFunctionExpression' || node.id === null
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/** Returns the outermost parenthesized expression holding a policy function. */
|
|
518
|
+
/** Returns a policy function's position through parentheses, object values, and array elements. */
|
|
523
519
|
export function functionToPolicyPosition(node: PolicyExpression): PolicyExpression {
|
|
524
520
|
let position = node
|
|
525
|
-
while (position.parent
|
|
526
|
-
|
|
521
|
+
while (position.parent !== undefined && position.parent !== null) {
|
|
522
|
+
const parent = position.parent
|
|
523
|
+
if (parent.type === 'ParenthesizedExpression') {
|
|
524
|
+
position = parent
|
|
525
|
+
continue
|
|
526
|
+
}
|
|
527
|
+
if (
|
|
528
|
+
parent.type === 'Property' &&
|
|
529
|
+
parent.kind === 'init' &&
|
|
530
|
+
parent.method === false &&
|
|
531
|
+
parent.computed !== true &&
|
|
532
|
+
parent.value === position &&
|
|
533
|
+
parent.parent?.type === 'ObjectExpression'
|
|
534
|
+
) {
|
|
535
|
+
position = parent.parent
|
|
536
|
+
continue
|
|
537
|
+
}
|
|
538
|
+
if (parent.type === 'ArrayExpression' && parent.elements?.includes(position) === true) {
|
|
539
|
+
position = parent
|
|
540
|
+
continue
|
|
541
|
+
}
|
|
542
|
+
break
|
|
527
543
|
}
|
|
528
544
|
return position
|
|
529
545
|
}
|
|
530
546
|
|
|
531
|
-
/** Reports whether a
|
|
547
|
+
/** Reports whether a literal position is admitted as an argument, return, or arrow body. */
|
|
548
|
+
export function isPolicyPosition(position: PolicyExpression): boolean {
|
|
549
|
+
const parent = position.parent
|
|
550
|
+
return (
|
|
551
|
+
((parent?.type === 'CallExpression' || parent?.type === 'NewExpression') &&
|
|
552
|
+
parent.arguments?.includes(position) === true) ||
|
|
553
|
+
(parent?.type === 'ReturnStatement' && parent.argument === position) ||
|
|
554
|
+
(parent?.type === 'ArrowFunctionExpression' && parent.body === position)
|
|
555
|
+
)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** Reports whether a function expression is passed as an argument through its literal position. */
|
|
532
559
|
export function isPolicyCallback(node: PolicyExpression): boolean {
|
|
533
|
-
if (
|
|
560
|
+
if (node.type !== 'ArrowFunctionExpression' && node.type !== 'FunctionExpression') return false
|
|
534
561
|
const position = functionToPolicyPosition(node)
|
|
535
562
|
const parent = position.parent
|
|
536
563
|
return (
|
|
537
564
|
(parent?.type === 'CallExpression' || parent?.type === 'NewExpression') &&
|
|
538
|
-
|
|
565
|
+
isPolicyPosition(position)
|
|
539
566
|
)
|
|
540
567
|
}
|
|
541
568
|
|
|
542
|
-
/** Reports whether a
|
|
569
|
+
/** Reports whether a function expression is returned as a result through its literal position. */
|
|
543
570
|
export function isPolicyResult(node: PolicyExpression): boolean {
|
|
544
|
-
if (
|
|
571
|
+
if (node.type !== 'ArrowFunctionExpression' && node.type !== 'FunctionExpression') return false
|
|
545
572
|
const position = functionToPolicyPosition(node)
|
|
546
573
|
const parent = position.parent
|
|
547
574
|
return (
|
|
548
|
-
(parent?.type === 'ReturnStatement'
|
|
549
|
-
(
|
|
575
|
+
(parent?.type === 'ReturnStatement' || parent?.type === 'ArrowFunctionExpression') &&
|
|
576
|
+
isPolicyPosition(position)
|
|
550
577
|
)
|
|
551
578
|
}
|
|
552
579
|
|
|
@@ -581,42 +608,6 @@ export function hasPolicyFunctionAncestor(node: PolicyExpression): boolean {
|
|
|
581
608
|
return method
|
|
582
609
|
}
|
|
583
610
|
|
|
584
|
-
/** Reports whether an arrow is the policy plugin's sanctioned visitor-table delegation. */
|
|
585
|
-
export function isPolicyVisitor(node: PolicyExpression): boolean {
|
|
586
|
-
const body = expressionToPolicyBody(node)
|
|
587
|
-
if (
|
|
588
|
-
node.type !== 'ArrowFunctionExpression' ||
|
|
589
|
-
node.expression !== true ||
|
|
590
|
-
body?.type !== 'CallExpression' ||
|
|
591
|
-
body.callee?.type !== 'Identifier' ||
|
|
592
|
-
typeof body.callee.name !== 'string' ||
|
|
593
|
-
!body.callee.name.startsWith('report')
|
|
594
|
-
) {
|
|
595
|
-
return false
|
|
596
|
-
}
|
|
597
|
-
const property = node.parent
|
|
598
|
-
const object = property?.parent
|
|
599
|
-
const returned = object?.parent
|
|
600
|
-
const block = returned?.parent
|
|
601
|
-
const create = block?.parent
|
|
602
|
-
const definition = create?.parent
|
|
603
|
-
return (
|
|
604
|
-
property?.type === 'Property' &&
|
|
605
|
-
property.method === false &&
|
|
606
|
-
property.value === node &&
|
|
607
|
-
object?.type === 'ObjectExpression' &&
|
|
608
|
-
returned?.type === 'ReturnStatement' &&
|
|
609
|
-
returned.argument === object &&
|
|
610
|
-
block?.type === 'BlockStatement' &&
|
|
611
|
-
create?.type === 'FunctionExpression' &&
|
|
612
|
-
definition?.type === 'Property' &&
|
|
613
|
-
definition.method === true &&
|
|
614
|
-
definition.value === create &&
|
|
615
|
-
definition.key?.type === 'Identifier' &&
|
|
616
|
-
definition.key.name === 'create'
|
|
617
|
-
)
|
|
618
|
-
}
|
|
619
|
-
|
|
620
611
|
/**
|
|
621
612
|
* Returns the module-scope statement that owns a policy function, or `undefined` when none does.
|
|
622
613
|
*
|
|
@@ -849,15 +840,17 @@ export function reportComments(context: PolicyContext): void {
|
|
|
849
840
|
|
|
850
841
|
/** Reports function syntax nested inside another function body. */
|
|
851
842
|
export function reportNested(context: PolicyContext, node: PolicyExpression): void {
|
|
852
|
-
if (
|
|
853
|
-
!hasPolicyFunctionAncestor(node) ||
|
|
854
|
-
isPolicyMethod(node) ||
|
|
855
|
-
isPolicyCallback(node) ||
|
|
856
|
-
isPolicyResult(node) ||
|
|
857
|
-
isPolicyVisitor(node)
|
|
858
|
-
) {
|
|
843
|
+
if (!hasPolicyFunctionAncestor(node) || isPolicyCallback(node) || isPolicyResult(node)) {
|
|
859
844
|
return
|
|
860
845
|
}
|
|
846
|
+
if (isPolicyMethod(node)) {
|
|
847
|
+
if (node.parent?.type === 'MethodDefinition') return
|
|
848
|
+
const object = node.parent?.parent
|
|
849
|
+
if (object?.type === 'ObjectExpression') {
|
|
850
|
+
const position = functionToPolicyPosition(object)
|
|
851
|
+
if (isPolicyPosition(position)) return
|
|
852
|
+
}
|
|
853
|
+
}
|
|
861
854
|
context.report({ node, messageId: 'nested' })
|
|
862
855
|
}
|
|
863
856
|
|
|
@@ -969,7 +962,16 @@ export function reportFunction(context: PolicyContext, node: PolicyExpression):
|
|
|
969
962
|
return
|
|
970
963
|
}
|
|
971
964
|
if (region.type !== 'VariableDeclaration') return
|
|
972
|
-
|
|
965
|
+
let position = node
|
|
966
|
+
while (position.parent?.type === 'ParenthesizedExpression') position = position.parent
|
|
967
|
+
// Module placement admits direct callbacks; a literal member still belongs in a function file.
|
|
968
|
+
if (
|
|
969
|
+
(node.type === 'ArrowFunctionExpression' || node.id === null) &&
|
|
970
|
+
functionToPolicyPosition(node) === position &&
|
|
971
|
+
(isPolicyCallback(node) || isPolicyResult(node))
|
|
972
|
+
) {
|
|
973
|
+
return
|
|
974
|
+
}
|
|
973
975
|
context.report({ node, messageId: 'function' })
|
|
974
976
|
}
|
|
975
977
|
|
|
@@ -1059,11 +1061,12 @@ export const NESTED_RULE: PolicyRuleInterface = {
|
|
|
1059
1061
|
meta: {
|
|
1060
1062
|
type: 'problem',
|
|
1061
1063
|
docs: {
|
|
1062
|
-
description:
|
|
1064
|
+
description:
|
|
1065
|
+
'Disallow nested functions except callbacks passed as arguments or returned as results, directly or as members of object or array literals in those positions.',
|
|
1063
1066
|
},
|
|
1064
1067
|
messages: {
|
|
1065
1068
|
nested:
|
|
1066
|
-
'Extract the function to module scope or make instance-bound work a method; only
|
|
1069
|
+
'Extract the function to module scope or make instance-bound work a method; only a callback passed as an argument or returned as the result, directly or as a member of an object or array literal in that position, may stay in a function body.',
|
|
1067
1070
|
},
|
|
1068
1071
|
},
|
|
1069
1072
|
create(context) {
|
|
@@ -132,16 +132,20 @@
|
|
|
132
132
|
"error",
|
|
133
133
|
{
|
|
134
134
|
"patterns": [
|
|
135
|
+
{
|
|
136
|
+
"regex": "^(?:@(?:src|app)/vue(?:[/?#]|$)|@orkestrel/[^/]+/vue(?:[/?#]|$)|(?:\\.\\./)+(?:vue|src/vue|app/vue)(?:[/?#]|$))",
|
|
137
|
+
"message": "src/core must not depend on Vue extension modules"
|
|
138
|
+
},
|
|
135
139
|
{
|
|
136
140
|
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
137
141
|
"message": "imports must not use machine-specific absolute paths"
|
|
138
142
|
},
|
|
139
143
|
{
|
|
140
|
-
"regex": "^(
|
|
144
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
141
145
|
"message": "imports must not use non-Node URL schemes"
|
|
142
146
|
},
|
|
143
147
|
{
|
|
144
|
-
"regex": "(?:^|/)(
|
|
148
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
145
149
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
146
150
|
},
|
|
147
151
|
{
|
|
@@ -180,16 +184,20 @@
|
|
|
180
184
|
"error",
|
|
181
185
|
{
|
|
182
186
|
"patterns": [
|
|
187
|
+
{
|
|
188
|
+
"regex": "^(?:(?:vue|vite)(?:[/?#]|$)|@(?:vue|vitejs)/|@(?:src|app)/vue(?:[/?#]|$)|@orkestrel/[^/]+/vue(?:[/?#]|$)|(?:\\.\\./)+(?:vue|src/vue|app/vue)(?:[/?#]|$))",
|
|
189
|
+
"message": "src/browser must not depend on Vue extension modules"
|
|
190
|
+
},
|
|
183
191
|
{
|
|
184
192
|
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
185
193
|
"message": "imports must not use machine-specific absolute paths"
|
|
186
194
|
},
|
|
187
195
|
{
|
|
188
|
-
"regex": "^(
|
|
196
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
189
197
|
"message": "imports must not use non-Node URL schemes"
|
|
190
198
|
},
|
|
191
199
|
{
|
|
192
|
-
"regex": "(?:^|/)(
|
|
200
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
193
201
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
194
202
|
},
|
|
195
203
|
{
|
|
@@ -217,6 +225,54 @@
|
|
|
217
225
|
]
|
|
218
226
|
}
|
|
219
227
|
},
|
|
228
|
+
{
|
|
229
|
+
"files": ["src/vue/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}"],
|
|
230
|
+
"rules": {
|
|
231
|
+
"no-restricted-imports": [
|
|
232
|
+
"error",
|
|
233
|
+
{
|
|
234
|
+
"patterns": [
|
|
235
|
+
{
|
|
236
|
+
"regex": "^(?:@src/(?:|[^/?#cbv][^/?#]*|c|c[^/?#o][^/?#]*|co|co[^/?#r][^/?#]*|cor|cor[^/?#e][^/?#]*|core[^/?#][^/?#]*|b|b[^/?#r][^/?#]*|br|br[^/?#o][^/?#]*|bro|bro[^/?#w][^/?#]*|brow|brow[^/?#s][^/?#]*|brows|brows[^/?#e][^/?#]*|browse|browse[^/?#r][^/?#]*|browser[^/?#][^/?#]*|v|v[^/?#u][^/?#]*|vu|vu[^/?#e][^/?#]*|vue[^/?#][^/?#]*)(?:[/?#]|$)|(?:\\.\\./)+(?:src/)?(?:[^/.scbv][^/.]*|s|s[^/.r][^/.]*|sr|sr[^/.c][^/.]*|src[^/.][^/.]*|c|c[^/.o][^/.]*|co|co[^/.r][^/.]*|cor|cor[^/.e][^/.]*|core[^/.][^/.]*|b|b[^/.r][^/.]*|br|br[^/.o][^/.]*|bro|bro[^/.w][^/.]*|brow|brow[^/.s][^/.]*|brows|brows[^/.e][^/.]*|browse|browse[^/.r][^/.]*|browser[^/.][^/.]*|v|v[^/.u][^/.]*|vu|vu[^/.e][^/.]*|vue[^/.][^/.]*)(?:/|$))",
|
|
237
|
+
"message": "Vue faces must not depend on sibling sheet faces"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
241
|
+
"message": "imports must not use machine-specific absolute paths"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
245
|
+
"message": "imports must not use non-Node URL schemes"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
249
|
+
"message": "internal import paths must not contain noncanonical dot segments"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"regex": "^(?:(?:\\./)+\\.\\.(?:/|$)|(?:\\.\\./)+(?:\\./)+)|//",
|
|
253
|
+
"message": "relative import paths must not contain normalized traversal segments"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"regex": "\\\\",
|
|
257
|
+
"message": "import paths must use portable forward slashes"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"regex": "^typescript(?:[/?#]|$)",
|
|
261
|
+
"message": "the in-process compiler API is not a surface the fleet uses"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"regex": "^(?:@app(?:[/?#]|$)|(?:\\.\\./)+app(?:[/?#]|$))",
|
|
265
|
+
"message": "src environments must not depend on private app modules"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"regex": "^(?:node:|(?:_(?:http_(?:agent|client|common|incoming|outgoing|server)|stream_(?:duplex|passthrough|readable|transform|wrap|writable)|tls_(?:common|wrap))|assert(?:/strict)?|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|diagnostics_channel|dns(?:/promises)?|domain|events|fs(?:/promises)?|http|http2|https|inspector(?:/promises)?|module|net|os|path(?:/(?:posix|win32))?|perf_hooks|process|punycode|querystring|readline(?:/promises)?|repl|sqlite|stream(?:/(?:consumers|promises|web))?|string_decoder|sys|timers(?:/promises)?|tls|trace_events|tty|url|util(?:/types)?|v8|vm|wasi|worker_threads|zlib)(?:[/?#]|$)|@src/server(?:[/?#]|$)|@orkestrel/[^/]+/server(?:[/?#]|$)|(?:\\.\\./)+(?:server|src/server|app/server)(?:[/?#]|$))",
|
|
269
|
+
"message": "src/vue must not depend on Node or server-only modules"
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
},
|
|
220
276
|
{
|
|
221
277
|
"files": ["src/server/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}"],
|
|
222
278
|
"rules": {
|
|
@@ -224,16 +280,20 @@
|
|
|
224
280
|
"error",
|
|
225
281
|
{
|
|
226
282
|
"patterns": [
|
|
283
|
+
{
|
|
284
|
+
"regex": "^(?:@(?:src|app)/vue(?:[/?#]|$)|@orkestrel/[^/]+/vue(?:[/?#]|$)|(?:\\.\\./)+(?:vue|src/vue|app/vue)(?:[/?#]|$))",
|
|
285
|
+
"message": "src/server must not depend on Vue extension modules"
|
|
286
|
+
},
|
|
227
287
|
{
|
|
228
288
|
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
229
289
|
"message": "imports must not use machine-specific absolute paths"
|
|
230
290
|
},
|
|
231
291
|
{
|
|
232
|
-
"regex": "^(
|
|
292
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
233
293
|
"message": "imports must not use non-Node URL schemes"
|
|
234
294
|
},
|
|
235
295
|
{
|
|
236
|
-
"regex": "(?:^|/)(
|
|
296
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
237
297
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
238
298
|
},
|
|
239
299
|
{
|
|
@@ -272,16 +332,20 @@
|
|
|
272
332
|
"error",
|
|
273
333
|
{
|
|
274
334
|
"patterns": [
|
|
335
|
+
{
|
|
336
|
+
"regex": "^(?:@(?:src|app)/vue(?:[/?#]|$)|@orkestrel/[^/]+/vue(?:[/?#]|$)|(?:\\.\\./)+(?:vue|src/vue|app/vue)(?:[/?#]|$))",
|
|
337
|
+
"message": "app/core must not depend on Vue extension modules"
|
|
338
|
+
},
|
|
275
339
|
{
|
|
276
340
|
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
277
341
|
"message": "imports must not use machine-specific absolute paths"
|
|
278
342
|
},
|
|
279
343
|
{
|
|
280
|
-
"regex": "^(
|
|
344
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
281
345
|
"message": "imports must not use non-Node URL schemes"
|
|
282
346
|
},
|
|
283
347
|
{
|
|
284
|
-
"regex": "(?:^|/)(
|
|
348
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
285
349
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
286
350
|
},
|
|
287
351
|
{
|
|
@@ -316,16 +380,20 @@
|
|
|
316
380
|
"error",
|
|
317
381
|
{
|
|
318
382
|
"patterns": [
|
|
383
|
+
{
|
|
384
|
+
"regex": "^(?:(?:vue|vite)(?:[/?#]|$)|@(?:vue|vitejs)/|@(?:src|app)/vue(?:[/?#]|$)|@orkestrel/[^/]+/vue(?:[/?#]|$)|(?:\\.\\./)+(?:vue|src/vue|app/vue)(?:[/?#]|$))",
|
|
385
|
+
"message": "app/browser must not depend on Vue extension modules"
|
|
386
|
+
},
|
|
319
387
|
{
|
|
320
388
|
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
321
389
|
"message": "imports must not use machine-specific absolute paths"
|
|
322
390
|
},
|
|
323
391
|
{
|
|
324
|
-
"regex": "^(
|
|
392
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
325
393
|
"message": "imports must not use non-Node URL schemes"
|
|
326
394
|
},
|
|
327
395
|
{
|
|
328
|
-
"regex": "(?:^|/)(
|
|
396
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
329
397
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
330
398
|
},
|
|
331
399
|
{
|
|
@@ -349,6 +417,50 @@
|
|
|
349
417
|
]
|
|
350
418
|
}
|
|
351
419
|
},
|
|
420
|
+
{
|
|
421
|
+
"files": ["app/vue/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}"],
|
|
422
|
+
"rules": {
|
|
423
|
+
"no-restricted-imports": [
|
|
424
|
+
"error",
|
|
425
|
+
{
|
|
426
|
+
"patterns": [
|
|
427
|
+
{
|
|
428
|
+
"regex": "^(?:@(?:src|app)/(?:|[^/?#cbv][^/?#]*|c|c[^/?#o][^/?#]*|co|co[^/?#r][^/?#]*|cor|cor[^/?#e][^/?#]*|core[^/?#][^/?#]*|b|b[^/?#r][^/?#]*|br|br[^/?#o][^/?#]*|bro|bro[^/?#w][^/?#]*|brow|brow[^/?#s][^/?#]*|brows|brows[^/?#e][^/?#]*|browse|browse[^/?#r][^/?#]*|browser[^/?#][^/?#]*|v|v[^/?#u][^/?#]*|vu|vu[^/?#e][^/?#]*|vue[^/?#][^/?#]*)(?:[/?#]|$)|(?:\\.\\./)+(?:src/|app/)?(?:[^/.sacbv][^/.]*|s|s[^/.r][^/.]*|sr|sr[^/.c][^/.]*|src[^/.][^/.]*|a|a[^/.p][^/.]*|ap|ap[^/.p][^/.]*|app[^/.][^/.]*|c|c[^/.o][^/.]*|co|co[^/.r][^/.]*|cor|cor[^/.e][^/.]*|core[^/.][^/.]*|b|b[^/.r][^/.]*|br|br[^/.o][^/.]*|bro|bro[^/.w][^/.]*|brow|brow[^/.s][^/.]*|brows|brows[^/.e][^/.]*|browse|browse[^/.r][^/.]*|browser[^/.][^/.]*|v|v[^/.u][^/.]*|vu|vu[^/.e][^/.]*|vue[^/.][^/.]*)(?:/|$))",
|
|
429
|
+
"message": "Vue faces must not depend on sibling sheet faces"
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
433
|
+
"message": "imports must not use machine-specific absolute paths"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
437
|
+
"message": "imports must not use non-Node URL schemes"
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
441
|
+
"message": "internal import paths must not contain noncanonical dot segments"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"regex": "^(?:(?:\\./)+\\.\\.(?:/|$)|(?:\\.\\./)+(?:\\./)+)|//",
|
|
445
|
+
"message": "relative import paths must not contain normalized traversal segments"
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"regex": "\\\\",
|
|
449
|
+
"message": "import paths must use portable forward slashes"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"regex": "^typescript(?:[/?#]|$)",
|
|
453
|
+
"message": "the in-process compiler API is not a surface the fleet uses"
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"regex": "^(?:node:|(?:_(?:http_(?:agent|client|common|incoming|outgoing|server)|stream_(?:duplex|passthrough|readable|transform|wrap|writable)|tls_(?:common|wrap))|assert(?:/strict)?|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|diagnostics_channel|dns(?:/promises)?|domain|events|fs(?:/promises)?|http|http2|https|inspector(?:/promises)?|module|net|os|path(?:/(?:posix|win32))?|perf_hooks|process|punycode|querystring|readline(?:/promises)?|repl|sqlite|stream(?:/(?:consumers|promises|web))?|string_decoder|sys|timers(?:/promises)?|tls|trace_events|tty|url|util(?:/types)?|v8|vm|wasi|worker_threads|zlib)(?:[/?#]|$)|@app/server(?:[/?#]|$)|@src/server(?:[/?#]|$)|@orkestrel/[^/]+/server(?:[/?#]|$)|(?:\\.\\./)+(?:server|src/server|app/server)(?:[/?#]|$))",
|
|
457
|
+
"message": "app/vue must not depend on Node or server-only modules"
|
|
458
|
+
}
|
|
459
|
+
]
|
|
460
|
+
}
|
|
461
|
+
]
|
|
462
|
+
}
|
|
463
|
+
},
|
|
352
464
|
{
|
|
353
465
|
"files": ["app/server/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}"],
|
|
354
466
|
"rules": {
|
|
@@ -356,16 +468,20 @@
|
|
|
356
468
|
"error",
|
|
357
469
|
{
|
|
358
470
|
"patterns": [
|
|
471
|
+
{
|
|
472
|
+
"regex": "^(?:@(?:src|app)/vue(?:[/?#]|$)|@orkestrel/[^/]+/vue(?:[/?#]|$)|(?:\\.\\./)+(?:vue|src/vue|app/vue)(?:[/?#]|$))",
|
|
473
|
+
"message": "app/server must not depend on Vue extension modules"
|
|
474
|
+
},
|
|
359
475
|
{
|
|
360
476
|
"regex": "^(?:/|[A-Za-z]:[\\\\/])",
|
|
361
477
|
"message": "imports must not use machine-specific absolute paths"
|
|
362
478
|
},
|
|
363
479
|
{
|
|
364
|
-
"regex": "^(
|
|
480
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
365
481
|
"message": "imports must not use non-Node URL schemes"
|
|
366
482
|
},
|
|
367
483
|
{
|
|
368
|
-
"regex": "(?:^|/)(
|
|
484
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
369
485
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
370
486
|
},
|
|
371
487
|
{
|
|
@@ -405,11 +521,11 @@
|
|
|
405
521
|
"message": "imports must not use machine-specific absolute paths"
|
|
406
522
|
},
|
|
407
523
|
{
|
|
408
|
-
"regex": "^(
|
|
524
|
+
"regex": "^(?:[A-Za-mo-z][A-Za-z0-9+.-]*|n(?:[A-Za-np-z0-9+.-][A-Za-z0-9+.-]*)?|no(?:[A-Za-ce-z0-9+.-][A-Za-z0-9+.-]*)?|nod(?:[A-Za-df-z0-9+.-][A-Za-z0-9+.-]*)?|node[A-Za-z0-9+.-]+):",
|
|
409
525
|
"message": "imports must not use non-Node URL schemes"
|
|
410
526
|
},
|
|
411
527
|
{
|
|
412
|
-
"regex": "(?:^|/)(
|
|
528
|
+
"regex": "(?:^|/)(?:[^/.][^/]*|\\.[^/.][^/]*|\\.\\.[^/]+)/\\.{1,2}(?:/|$)",
|
|
413
529
|
"message": "internal import paths must not contain noncanonical dot segments"
|
|
414
530
|
},
|
|
415
531
|
{
|
|
@@ -433,7 +549,7 @@
|
|
|
433
549
|
"message": "src/bin must not depend on private app modules"
|
|
434
550
|
},
|
|
435
551
|
{
|
|
436
|
-
"regex": "^(?:(?:vue|vite)(?:[/?#]|$)|@(?:vue|vitejs)/|@src/browser(?:[/?#]|$)|@orkestrel/[^/]+/browser(?:[/?#]|$)|(?:\\.\\./)+(?:browser|src/browser|app/browser)(?:[/?#]|$))",
|
|
552
|
+
"regex": "^(?:(?:vue|vite)(?:[/?#]|$)|@(?:vue|vitejs)/|@src/(?:browser|vue)(?:[/?#]|$)|@orkestrel/[^/]+/(?:browser|vue)(?:[/?#]|$)|(?:\\.\\./)+(?:browser|vue|src/(?:browser|vue)|app/browser)(?:[/?#]|$))",
|
|
437
553
|
"message": "src/bin must not depend on browser-only modules"
|
|
438
554
|
}
|
|
439
555
|
]
|
|
@@ -446,7 +562,7 @@
|
|
|
446
562
|
"tests/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}",
|
|
447
563
|
"configs/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}",
|
|
448
564
|
"scripts/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}",
|
|
449
|
-
"
|
|
565
|
+
"./*.{cjs,cts,js,mjs,mts,ts}"
|
|
450
566
|
],
|
|
451
567
|
"rules": {
|
|
452
568
|
"no-restricted-imports": [
|
|
@@ -16,15 +16,19 @@ guide mirrors, and the `WriteTransaction` those writes stage through. The `scaff
|
|
|
16
16
|
([`src/bin`](../src/bin)) publishes no barrel, so it is documented in prose and sits outside the
|
|
17
17
|
surface bijection.
|
|
18
18
|
|
|
19
|
-
The [Blueprint reference](scaffold.md#blueprint) describes the journey axis and its adopter-edited
|
|
20
|
-
`configs/app/vite.journey.config.ts` wrapper, the `SetupRuntime` list, and the `setup:browser`
|
|
21
|
-
project. The generated workspace runs journey variants and browser setup proofs through its
|
|
22
|
-
`test` chain.
|
|
23
|
-
|
|
24
19
|
That bijection is the row's contract, and [`tests/guides.test.ts`](../tests/guides.test.ts)
|
|
25
20
|
enforces it: every symbol the guide documents exists in the core barrel or the server barrel, and
|
|
26
21
|
every symbol either barrel exports is documented.
|
|
27
22
|
|
|
23
|
+
The [Blueprint reference](scaffold.md#blueprint) describes the structural facts, the
|
|
24
|
+
`SetupRuntime` list, and the `setup:browser` project. The
|
|
25
|
+
[surfaces and extensions reference](scaffold.md#surfaces-and-extensions) describes the browser
|
|
26
|
+
surface with its journey and showcase modes, the styles surface with its themes target, the `vue`
|
|
27
|
+
faces and named-sheet extensions, the creation options, their refusals, and the advisories on a
|
|
28
|
+
declared selection, the marker each fact is read from, the ownership of every path a sheet face
|
|
29
|
+
emits, the page stamp, the external resolution of each published face, the vendored proofs, the
|
|
30
|
+
root setup mirror, and the migration guard. Both sections belong to the `scaffold.md` row.
|
|
31
|
+
|
|
28
32
|
## By directory
|
|
29
33
|
|
|
30
34
|
| Directory | Guide |
|
|
@@ -125,6 +125,7 @@ directly.
|
|
|
125
125
|
| `computeSymbolKey` | function | `(symbol: SurfaceSymbol) => string` | Computes the bijection key for a surface symbol — `${keyword} ${name}` — so a symbol-set comparison diffs (name, keyword) pairs rather than names alone. |
|
|
126
126
|
| `findMissing` | function | `(names: readonly string[], source: readonly string[]) => readonly string[]` | Finds the names present in `names` but absent from `source` — the set-difference behind a both-directions bijection assertion. |
|
|
127
127
|
| `findMissingSymbols` | function | `(symbols: readonly SurfaceSymbol[], source: readonly SurfaceSymbol[]) => readonly string[]` | Finds the symbol-key set-difference between two symbol lists — `symbols` present but absent from `source`, compared by `computeSymbolKey` so a symbol can drift in neither name nor keyword. |
|
|
128
|
+
| `hasBehaviouralSurface` | function | `(source: SourceInterface) => boolean` | Checks whether a source declares at least one behavioural member — a `class` or `interface` in its surface that carries a call-signature member — so a guide owes a `## Methods` group only where the source has one to document. |
|
|
128
129
|
| `extractSourceLines` | function | `(source: string) => readonly SourceLine[]` | Extracts aligned physical source-line records in one character traversal. Real line and block comments and complete template tokens become spaces in `SourceLine.code`, while ordinary code, quoted strings, and recognized regex literals retain their columns. Genuine JSDoc opened from reflection code is retained span by span at its exact physical column in `SourceLine.jsdoc`; faux openers in comments and templates are excluded. Membership remains each consumer's separate anchored grammar. |
|
|
129
130
|
| `extractExports` | function | `(source: string) => readonly SurfaceSymbol[]` | Extracts the module-scope exports declared in one file's source text — the declaration keys `collectKeys` reports, each split back into the keyword and name that built it, deduped by (keyword, name). |
|
|
130
131
|
| `extractHidden` | function | `(source: string) => readonly SurfaceSymbol[]` | Extracts the module-scope declarations lacking the `export` keyword in one file's source text — the mirror image of `extractExports`'s grammar, anchored the same way (column 0, so an indented inner declaration never matches). |
|
|
@@ -663,7 +664,9 @@ guard so a renamed heading fails loudly instead of passing on an empty extractio
|
|
|
663
664
|
missing; a link naming a fixture directory resolves on the same directory rule. Guard:
|
|
664
665
|
`guide.tests().length > 0`.
|
|
665
666
|
- **NV — Non-vacuousness.** `parseManifest` yields at least one entry; each guide's
|
|
666
|
-
`surface()` and every `MethodGroup` is non-empty — the guard behind every other check.
|
|
667
|
+
`surface()` and every `MethodGroup` is non-empty — the guard behind every other check. A guide
|
|
668
|
+
with no `MethodGroup` at all is reported only where `hasBehaviouralSurface` finds a surface
|
|
669
|
+
`class` or `interface` with a member to document; a source of constants and types owes none.
|
|
667
670
|
- **FL — Fence-language listing.** `findUnlisted(guide.fences(), LANGUAGES)` keeps every fence
|
|
668
671
|
whose language the package did not list, plus every untagged fence. The list is the package's
|
|
669
672
|
own — `Guide` never decides it — so a package documenting `sh` or `sql` examples lists those
|