@orkestrel/scaffold 0.0.107 → 0.0.108

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.
Files changed (42) hide show
  1. package/dist/agents/skills/orkestrel-dispatch/scripts/sweep.js +124 -4
  2. package/dist/bin/main.js +1 -1
  3. package/dist/bin/main.js.map +1 -1
  4. package/dist/host/AGENTS.md +5 -1
  5. package/dist/host/agents/orchestration.md +60 -45
  6. package/dist/host/agents/platforms/posix.md +15 -0
  7. package/dist/host/agents/platforms/windows.md +37 -0
  8. package/dist/host/agents/skills/orkestrel-debrief/references/retention.md +10 -10
  9. package/dist/host/agents/skills/orkestrel-dispatch/SKILL.md +6 -5
  10. package/dist/host/agents/skills/orkestrel-dispatch/references/launch.md +12 -8
  11. package/dist/host/agents/skills/orkestrel-dispatch/scripts/sweep.ts +144 -4
  12. package/dist/host/agents/skills/orkestrel-parallel/SKILL.md +67 -10
  13. package/dist/host/agents/skills/orkestrel-parallel/agents/openai.yaml +2 -2
  14. package/dist/host/agents/skills/orkestrel-parallel/references/claude.md +32 -0
  15. package/dist/host/agents/skills/orkestrel-parallel/references/codex.md +28 -0
  16. package/dist/host/agents/skills/orkestrel-parallel/references/cursor.md +29 -0
  17. package/dist/host/agents/skills/orkestrel-parallel/references/t3.md +31 -0
  18. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +2 -1
  19. package/dist/host/agents/transports/codex.md +1 -1
  20. package/dist/host/claude/AGENTS.md +6 -9
  21. package/dist/host/claude/rules/campaign.md +55 -0
  22. package/dist/host/claude/rules/documentation.md +2 -0
  23. package/dist/host/claude/rules/portability.md +1 -2
  24. package/dist/host/claude/rules/typescript.md +1 -1
  25. package/dist/host/claude/rules/writing.md +5 -2
  26. package/dist/host/claude/skills/orkestrel-parallel/SKILL.md +1 -1
  27. package/dist/host/codex/config.toml +3 -3
  28. package/dist/host/configs/policy.ts +106 -1
  29. package/dist/host/cursor/rules/orchestration.mdc +1 -0
  30. package/dist/host/dotfiles/oxlintrc.json +4 -2
  31. package/dist/host/guides/scaffold.md +56 -1
  32. package/dist/host/manifest.json +64 -27
  33. package/dist/host/tests/config.test.ts +560 -5
  34. package/dist/host/tests/setupPolicy.ts +496 -6
  35. package/dist/src/core/index.cjs +26 -2
  36. package/dist/src/core/index.cjs.map +1 -1
  37. package/dist/src/core/index.d.cts +1 -1
  38. package/dist/src/core/index.d.ts +1 -1
  39. package/dist/src/core/index.js +26 -2
  40. package/dist/src/core/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/host/agents/skills/orkestrel-parallel/references/harnesses.md +0 -19
@@ -0,0 +1,55 @@
1
+ ---
2
+ paths:
3
+ - '.orkestrel/**/*'
4
+ ---
5
+
6
+ # Campaign folder rules
7
+
8
+ `.orkestrel/` is the tracked record of a live campaign: everything a session on another machine, under another harness, needs to resume the work. `.agents/orchestration.md` owns how agents run. This file owns what the folder holds, how to write it, and how a session starts from it.
9
+
10
+ ## Layout
11
+
12
+ | Path | Holds |
13
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
14
+ | `.orkestrel/<package>/` | one package's live campaign |
15
+ | `.orkestrel/plan.md` | the fleet campaign's plan: goal, exit criterion, packages, layer order, and the units each package owes |
16
+ | `.orkestrel/ledger.md` | the fleet campaign's ledger |
17
+ | `.orkestrel/release.md` | the live release wave: its layers, each package's bump ruling with its evidence, the round each package landed in, and standing readings |
18
+
19
+ A package directory holds:
20
+
21
+ | File | Holds | When |
22
+ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
23
+ | `plan.md` | a concise goal and exit criterion that serve as a goal prompt, each repository the campaign changes by name and URL, § State, open decisions, deferred triggers, § Sequence | always |
24
+ | `ledger.md` | one row per dispatched unit and per user ruling on routing or scope: date, unit, role, carrier | always |
25
+ | `README.md` | the file map, the read order, and the id law | when the folder holds more than `plan.md` and `ledger.md` |
26
+ | `tenets.md` | the campaign's standing directives | when the campaign has any |
27
+ | `ideas.md`, `gaps.md` | ideas set aside and library gaps, each numbered for life with its reason and its reopen trigger | when the campaign records any |
28
+ | `designs/`, `research/` | one design or research record per subject | when a chunk needs one |
29
+ | a verdict file | the verdict of an open seam | until the seam closes |
30
+
31
+ - Write a file about one package under that package's directory, and a file about two or more packages at the top level.
32
+ - Name a ledger row's lane by its role in `.agents/orchestration.md` § Roles. Write no row for the Orchestrator's own commit.
33
+
34
+ ## Content
35
+
36
+ - Track every file under `.orkestrel/`. Cite a tracked file, a commit, or a published URL. Cite no git-ignored path, no agent memory, and no path outside the repository; name a sibling repository by its package name and a path inside it.
37
+ - Name no harness, model, provider, harness tool, operating system, shell, or machine as the host or engine of the work. Name a lane by its role. A product statement about a host family follows `.claude/rules/portability.md` § Claims.
38
+ - Write every line as a directive, a fact, or a table cell, per `.claude/rules/writing.md` § Instruction files: absolute dates, one home per fact, a tree location by symbol and file. A decision or a measurement lives in the commit that made it; cite the commit.
39
+ - Keep live state out: engine availability, session ownership, process ids, installed versions, and another repository's state live in the roster, `package.json`, and that repository.
40
+ - Keep unit briefs, reports, journals, and drafts under the checkout's `tmp/` (`.agents/orchestration.md` § tmp layout); that file's § Cleanup owns what a unit's files carry before they go.
41
+ - Record a prepared, unapplied change as text in `plan.md` or as a commit, never as a pointer to scratch.
42
+
43
+ ## Start a session
44
+
45
+ 1. Read the package folder's `README.md` when present, then `plan.md` § State, then the first open chunk of § Sequence.
46
+ 2. Run `git status --porcelain -b`, `git log @{upstream}..`, and `node .agents/skills/orkestrel-dispatch/scripts/sweep.ts --report`. Reconcile each difference with § State before you act.
47
+ 3. Act only on what the folder, the tree, and git hold. Agent memory from another machine or harness is absent.
48
+
49
+ ## Hand off and close
50
+
51
+ - Keep `plan.md` § State current at every commit, and make its last line the next action.
52
+ - Before a session ends or its context compacts, write each ruling, decision, and next action into the folder; `.agents/orchestration.md` § Memory owns what memory can hold.
53
+ - When a chunk closes, remove it from § Sequence. Its closing commit carries its evidence, and § State names the commit.
54
+ - Delete a verdict file when its seam closes.
55
+ - At acceptance, move each file that outlives the campaign to its root home, retarget its citations in the same change, and delete the package directory per `.agents/skills/orkestrel-debrief/references/retention.md`. Delete a top-level file when the wave or fleet campaign it records closes.
@@ -86,6 +86,8 @@ Never use in-repository `@src/*` aliases in public guide examples; reserve them
86
86
  - Name a skill directory `orkestrel-<word>`: the prefix and one word naming the process or the subject, such as `orkestrel-harden` or `orkestrel-journey`. Never a second word.
87
87
  - For a portable skill that teaches an external framework, takes the host project's own `AGENTS.md` file as its code law, and binds none of this repository's rule files, drop the `orkestrel-` prefix and name the skill for the framework a reader searches for. Add no other exception. The `enterprise-bootstrap` skill meets that test and keeps its name: it carries Bootstrap 5.3 craft, assumes no stack, and names the `.agents/orchestration.md` and `.claude/rules/quality.md` files only where they are present. Do not rename it into the namespace.
88
88
  - Keep `SKILL.md` concise and route conditional detail to one-level `references/`.
89
+ - In a `SKILL.md`, name another skill's reference by that skill and the reference's title, never as a `references/<name>.md` path; the policy sweep attributes that token to the citing skill.
90
+ - When you add a canonical skill, register it in `TARGET_SKILL_NAMES` in `src/core/constants.ts`, in the skill lists of `tests/distribution.test.ts`, `tests/src/core/Compiler.test.ts`, and `tests/src/core/compilers.test.ts`, and in the pointer-file count of `tests/src/bin/CLI.test.ts`, then regenerate `host.json` with a build.
89
91
  - Name every Markdown file in a skill's `references/` from its `SKILL.md`, and delete a reference nothing names.
90
92
  - Frontmatter contains only `name` and a trigger-focused `description`.
91
93
  - Set `name` to the skill's own directory name.
@@ -9,7 +9,6 @@ paths:
9
9
  - 'guides/**/*'
10
10
  - 'package.json'
11
11
  - '.gitattributes'
12
- - '.github/workflows/*'
13
12
  ---
14
13
 
15
14
  # Host portability rules
@@ -99,7 +98,7 @@ and the form of a conditional skip.
99
98
 
100
99
  ## Claims
101
100
 
102
- - Never describe the suite, the host, or CI as POSIX. Name the host and the date behind a reading.
101
+ - Never describe the suite or the host as POSIX. Name the host and the date behind a reading.
103
102
  - Run the gate chain on each host a change claims, and record a reading that could not run as a
104
103
  limit naming the host it needs.
105
104
  - Keep a POSIX-shaped `file:///` literal in a guide only as an opaque fictional identifier. Build
@@ -233,7 +233,7 @@ type Result<T, E = Error> = Success<T> | Failure<E>
233
233
  ## Comments and API documentation
234
234
 
235
235
  - Comments explain why, never restate what self-explanatory code does. The Writing rules in `AGENTS.md` and `.claude/rules/writing.md` govern their prose.
236
- - Every public export has complete TSDoc: description, `@param`, `@returns`, and `@example` where applicable.
236
+ - Every public export has TSDoc, because the package guide is built from it: a one-sentence summary; `@param`, `@returns`, or a thrown-error line only where the signature leaves the meaning open; and an `@example` of typical use, as short as it can be while still showing the call and its result.
237
237
  - The first sentence states what the symbol does in the third person with an `-s` verb — `Creates`,
238
238
  `Returns`, `Checks whether` — and never repeats the symbol's name.
239
239
  - `policy/no-malformed-summary` reads that first sentence over every doc block a top-level export
@@ -1,6 +1,9 @@
1
1
  # Writing rules
2
2
 
3
- `AGENTS.md` § Writing governs every reply. This file adds what developer prose, comments, and instruction files decide. Write prose after the code works, and keep it short.
3
+ `AGENTS.md` § Writing governs every reply. This file adds what developer prose, comments, and instruction files decide.
4
+
5
+ - Write comments, TSDoc, and guide prose once, after types, tests, and implementation are final, and keep them minimal. Prose written earlier is wrong by the time the implementation settles.
6
+ - Never revise, review, or gate prose while the implementation can still change.
4
7
 
5
8
  ## Voice
6
9
 
@@ -43,7 +46,7 @@
43
46
 
44
47
  ## Code comments
45
48
 
46
- - A comment states why, never what the code shows. Delete a comment that restates the line. Do not narrate history, alternatives tried, or a probe's result.
49
+ - Write a comment only where the code cannot show why, in one line. Delete a comment that restates the line. Do not narrate history, alternatives tried, or a probe's result.
47
50
  - Write TSDoc only where `.claude/rules/typescript.md` requires it, in its prescribed shape, and no longer than the contract needs.
48
51
 
49
52
  ## Instruction files
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: orkestrel-parallel
3
3
  description: >-
4
- Coordinate independently owned writer lanes in one checkout through messages, with one runner for checks and an Orchestrator for decisions. Use when implementation units can progress in parallel with disjoint files or explicit regions of shared files. Serialize overlapping edits and hold every input needed for a reliable measurement. Require shared files and a channel that can wake an idle lane.
4
+ Run parallel work: lanes inside one session (subagents, child tasks, background commands) and peer sessions that share a checkout, a machine, or an execution lane. Use when units can progress in parallel, when another session works on the same machine or checkout, or before the first lane on a harness. Bound the host, keep lanes visible, coordinate writers through messages with one runner for checks, and hand a shared execution lane over in one message. Each harness page records its mechanics and quirks; a harness with no page carries no writer or runner lane until its bring-up questions are answered on one.
5
5
  ---
6
6
 
7
7
  # Load the canonical workflow
@@ -15,9 +15,9 @@ files you touch; Codex does not load them for you. Follow a skill under .agents/
15
15
  trigger fires.
16
16
 
17
17
  Use the role mapping and continuation rules in .agents/orchestration.md. Before using native or
18
- T3 collaboration, read .agents/skills/orkestrel-parallel/references/harnesses.md for the channel
19
- mechanics and retained identifiers, and read the installed tool descriptions before relying on a
20
- capability that reference names.
18
+ T3 collaboration, read .agents/skills/orkestrel-parallel/references/codex.md and t3.md for the
19
+ channel mechanics, retained identifiers, and quirks, and read the installed tool descriptions
20
+ before relying on a capability those pages name. .agents/platforms/ owns the host shell.
21
21
 
22
22
  Hooks: .codex/hooks.json runs the orkestrel-dispatch sweep script (node
23
23
  .agents/skills/orkestrel-dispatch/scripts/sweep.ts --report) on SessionStart and git diff --check
@@ -28,7 +28,7 @@ export interface PolicyExpression extends PolicyNode {
28
28
  readonly declaration?: PolicyExpression
29
29
  readonly declarations?: readonly PolicyExpression[]
30
30
  readonly init?: PolicyExpression | null
31
- readonly source?: PolicyExpression
31
+ readonly source?: PolicyExpression | null
32
32
  readonly specifiers?: readonly PolicyExpression[]
33
33
  readonly imported?: PolicyExpression
34
34
  readonly exported?: PolicyExpression
@@ -116,6 +116,9 @@ export interface PolicyVisitor {
116
116
  readonly FunctionExpression?: (node: PolicyNode) => void
117
117
  readonly ArrowFunctionExpression?: (node: PolicyNode) => void
118
118
  readonly ImportDeclaration?: (node: PolicyNode) => void
119
+ readonly ImportExpression?: (node: PolicyNode) => void
120
+ readonly ExportNamedDeclaration?: (node: PolicyNode) => void
121
+ readonly ExportAllDeclaration?: (node: PolicyNode) => void
119
122
  readonly MemberExpression?: (node: PolicyNode) => void
120
123
  readonly MethodDefinition?: (node: PolicyNode) => void
121
124
  readonly PropertyDefinition?: (node: PolicyNode) => void
@@ -205,9 +208,25 @@ export const DATA_EXEMPT_FILES: readonly string[] = Object.freeze(['helpers.ts']
205
208
  /** Lists the fleet-registered folders whose direct modules each contain one named function. */
206
209
  export const FUNCTION_DOMAIN_FOLDERS: readonly string[] = Object.freeze([
207
210
  'app/browser/composables',
211
+ 'app/vue/composables',
208
212
  'src/server/execution',
209
213
  ])
210
214
 
215
+ /** Lists the published destinations a Vue relative import may reach before independent restrictions. */
216
+ export const VUE_SOURCE_ROOTS: readonly string[] = Object.freeze([
217
+ 'src/core',
218
+ 'src/browser',
219
+ 'src/vue',
220
+ ])
221
+
222
+ /** Lists the additional private destinations an application Vue relative import may reach. */
223
+ export const VUE_APPLICATION_ROOTS: readonly string[] = Object.freeze([
224
+ ...VUE_SOURCE_ROOTS,
225
+ 'app/core',
226
+ 'app/browser',
227
+ 'app/vue',
228
+ ])
229
+
211
230
  /** Lists the registered function-domain names no source file may take as its stem. */
212
231
  export const FUNCTION_DOMAIN_NAMES: readonly string[] = Object.freeze(
213
232
  FUNCTION_DOMAIN_FOLDERS.map((folder) => folder.slice(folder.lastIndexOf('/') + 1)),
@@ -439,6 +458,69 @@ export function pathToPolicyRelative(filename: string, cwd: string): string {
439
458
  return normalizedFile.startsWith(prefix) ? normalizedFile.slice(prefix.length) : normalizedFile
440
459
  }
441
460
 
461
+ /**
462
+ * Computes a lexical workspace-relative destination from an absolute Vue importer and its cwd.
463
+ * Refuses unclassifiable locations, noncanonical relative segments, and traversal above the
464
+ * workspace. Query and fragment text is excluded from the path without decoding it; callers retain
465
+ * the original specifier for independent restrictions. No filesystem or module resolution occurs.
466
+ */
467
+ export function computePolicyTarget(
468
+ filename: string,
469
+ cwd: string,
470
+ specifier: string,
471
+ ): string | undefined {
472
+ const relative = pathToPolicyRelative(filename, cwd)
473
+ const location = relative.split('/')
474
+ if (
475
+ !/^(?:\/|[A-Za-z]:\/)/u.test(cwd.replaceAll('\\', '/')) ||
476
+ /(?:^|\/)\.{1,2}(?:\/|$)/u.test(cwd.replaceAll('\\', '/')) ||
477
+ relative === filename.replaceAll('\\', '/') ||
478
+ location.length < 3 ||
479
+ (location[0] !== 'src' && location[0] !== 'app') ||
480
+ location[1] !== 'vue' ||
481
+ location.some((part) => part === '' || part === '.' || part === '..')
482
+ ) {
483
+ return undefined
484
+ }
485
+ const path = specifier.split(/[?#]/u)[0] ?? ''
486
+ if (!/^\.{1,2}(?:\/|$)/u.test(path) || path.includes('\\') || path.includes('//')) {
487
+ return undefined
488
+ }
489
+ const parts = path.replace(/\/$/u, '').split('/')
490
+ const first = parts.findIndex((part) => part !== '.' && part !== '..')
491
+ const boundary = first === -1 ? parts.length : first
492
+ const leading = parts.slice(0, boundary)
493
+ const parents = leading.filter((part) => part === '..').length
494
+ const remaining = parts.slice(boundary)
495
+ const directory = pathToPolicyFolder(relative).split('/')
496
+ if (
497
+ (parents === 0 && leading.length !== 1) ||
498
+ (parents !== 0 && parents !== leading.length) ||
499
+ parents > directory.length ||
500
+ remaining.some((part) => part === '' || part === '.' || part === '..')
501
+ ) {
502
+ return undefined
503
+ }
504
+ return [...directory.slice(0, directory.length - parents), ...remaining].join('/')
505
+ }
506
+
507
+ /** Reports a literal relative import or re-export whose actual destination leaves its Vue boundary. */
508
+ export function reportVueImport(context: PolicyContext, node: PolicyExpression): void {
509
+ const source = node.source
510
+ if (source?.type !== 'Literal' || typeof source.value !== 'string') return
511
+ if (!/^\.{1,2}(?:[/?#]|$)/u.test(source.value)) return
512
+ const target = computePolicyTarget(context.filename, context.cwd, source.value)
513
+ const roots = pathToPolicyRelative(context.filename, context.cwd).startsWith('app/vue/')
514
+ ? VUE_APPLICATION_ROOTS
515
+ : VUE_SOURCE_ROOTS
516
+ if (
517
+ target !== undefined &&
518
+ roots.some((root) => target === root || target.startsWith(root + '/'))
519
+ )
520
+ return
521
+ context.report({ node, messageId: 'vue' })
522
+ }
523
+
442
524
  /** Returns the extensionless stem of one policy file name. */
443
525
  export function fileToPolicyStem(file: string): string {
444
526
  const boundary = file.lastIndexOf('.')
@@ -1399,6 +1481,28 @@ export const DOMAIN_RULE: PolicyRuleInterface = {
1399
1481
  },
1400
1482
  }
1401
1483
 
1484
+ /** Bans literal relative imports and re-exports outside the importing Vue face's permitted roots. */
1485
+ export const VUE_IMPORT_RULE: PolicyRuleInterface = {
1486
+ meta: {
1487
+ type: 'problem',
1488
+ docs: {
1489
+ description:
1490
+ 'Disallow Vue relative imports outside the faces their importing file may reach.',
1491
+ },
1492
+ messages: {
1493
+ vue: 'Keep this Vue relative import within the permitted source and application faces.',
1494
+ },
1495
+ },
1496
+ create(context) {
1497
+ return {
1498
+ ImportDeclaration: (node) => reportVueImport(context, node),
1499
+ ImportExpression: (node) => reportVueImport(context, node),
1500
+ ExportNamedDeclaration: (node) => reportVueImport(context, node),
1501
+ ExportAllDeclaration: (node) => reportVueImport(context, node),
1502
+ }
1503
+ },
1504
+ }
1505
+
1402
1506
  /** Bans host-specific line-ending handling. */
1403
1507
  export const ENDING_RULE: PolicyRuleInterface = {
1404
1508
  meta: {
@@ -1478,6 +1582,7 @@ export default {
1478
1582
  'no-misnamed-factory': FACTORY_RULE,
1479
1583
  'no-misnamed-plugin': PLUGIN_RULE,
1480
1584
  'no-malformed-domain': DOMAIN_RULE,
1585
+ 'no-cross-vue-face': VUE_IMPORT_RULE,
1481
1586
  'no-host-line-endings': ENDING_RULE,
1482
1587
  'no-malformed-summary': VOICE_RULE,
1483
1588
  'no-banned-term': TERM_RULE,
@@ -11,6 +11,7 @@ alwaysApply: true
11
11
 
12
12
  - Invoked through the `grok` bridge (`agent -p --mode=ask`): act as a read-only executor. Return distilled evidence with `file:line` pointers. Never edit, decide, or accept.
13
13
  - Driven by the user: act as the Orchestrator per `.agents/orchestration.md`, on Grok.
14
+ - `.agents/skills/orkestrel-parallel/references/cursor.md` owns Cursor's lane mechanics and quirks; `.agents/platforms/` owns the host shell.
14
15
 
15
16
  ## Reaching the other engines
16
17
 
@@ -401,12 +401,13 @@
401
401
  {
402
402
  "files": ["src/vue/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}"],
403
403
  "rules": {
404
+ "policy/no-cross-vue-face": "error",
404
405
  "no-restricted-imports": [
405
406
  "error",
406
407
  {
407
408
  "patterns": [
408
409
  {
409
- "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[^/.][^/.]*)(?:/|$))",
410
+ "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[^/?#][^/?#]*)(?:[/?#]|$))",
410
411
  "message": "Vue faces must not depend on sibling sheet faces"
411
412
  },
412
413
  {
@@ -605,12 +606,13 @@
605
606
  {
606
607
  "files": ["app/vue/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}"],
607
608
  "rules": {
609
+ "policy/no-cross-vue-face": "error",
608
610
  "no-restricted-imports": [
609
611
  "error",
610
612
  {
611
613
  "patterns": [
612
614
  {
613
- "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[^/.][^/.]*)(?:/|$))",
615
+ "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[^/?#][^/?#]*)(?:[/?#]|$))",
614
616
  "message": "Vue faces must not depend on sibling sheet faces"
615
617
  },
616
618
  {
@@ -1416,6 +1416,15 @@ executable, installs it, runs its checks, builds, projects, journey modes, showc
1416
1416
  export consumption, and proves that `repair` restores a deleted wrapper byte for byte and that
1417
1417
  `audit` reports a stale one.
1418
1418
 
1419
+ The default `appServer` build emits the single `dist/app/server/main.cjs` that a single-executable
1420
+ embed takes; its dynamic import evaluates only when it runs. The factory defaults `codeSplitting`
1421
+ to `false` on outputs that omit it. An override keeps its output members and explicit splitting
1422
+ values, so an overridden build can emit several files. The vendored `tests/config.test.ts` builds a
1423
+ scratch entry through the real wrapper in each target that holds `app/server`, requires one chunk,
1424
+ and splits it under a control. Scaffold's `tests/src/core/templates.test.ts` runs the emitted file in a staged
1425
+ server root, builds explicit output lists through the factory parameter, and runs the vendored case
1426
+ in staged server targets under a mutation of the factory and of the control.
1427
+
1419
1428
  ### The migration guard
1420
1429
 
1421
1430
  Vue code belongs to the `vue` extension's faces. `repair` and `overwrite` refuse a target whose
@@ -1623,6 +1632,52 @@ fetched bytes rather than prose this workspace wrote, and it reports a top-level
1623
1632
  neither this package's own, nor `guides/README.md`, nor a catalog row, so an exclusion always
1624
1633
  carries its evidence.
1625
1634
 
1635
+ The Vue override populations enable `policy/no-cross-vue-face` for `cjs`, `cts`, `js`, `jsx`,
1636
+ `mjs`, `mts`, `ts`, `tsx`, and Vue single-file components. The import-free `configs/policy.ts`
1637
+ leaf uses these local exports:
1638
+
1639
+ | Export | Behaviour |
1640
+ | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1641
+ | `computePolicyTarget` | Computes a lexical destination from the native importer's absolute filename and cwd, consuming relative parents against its actual directory. |
1642
+ | `reportVueImport` | Checks a literal source against complete permitted face roots, refusing unclassifiable locations and traversal above the workspace. |
1643
+ | `VUE_IMPORT_RULE` | Visits parser-admitted static imports, source-bearing named and star exports, their type-only forms, and string-literal dynamic imports through Oxlint's native parser. |
1644
+ | `VUE_SOURCE_ROOTS`, `VUE_APPLICATION_ROOTS` | Hold the frozen destination roots checked before the retained independent restrictions. |
1645
+
1646
+ Native grammar applies before policy visitors. In the canonical fixtures on both Vue faces, `.cjs` static
1647
+ value imports, named and star exports at both importer depths, and the source-less export receive
1648
+ native parser errors. The coverage keeps all original input identities and extensions in a disjoint
1649
+ partition: those seven inputs per face have explicit parser-refusal expectations on both Vue faces;
1650
+ the remaining inputs retain strict rule and collection checks. The `.cjs` literal dynamic imports
1651
+ and nonliteral import controls stay in that parsed population. No `.cts` or other extension inherits
1652
+ a refusal from the `.cjs` observation; each must establish its own native parsing and collection.
1653
+
1654
+ Otherwise-permitted relative imports within `src/vue` or `app/vue` work at arbitrary nesting
1655
+ depth. A nested `../print/index.js` can stay inside Vue while the same text at the face root
1656
+ reaches a forbidden sibling. Application Vue retains relative access to `app/core`, `app/browser`,
1657
+ `src/core`, `src/browser`, and `src/vue`; published Vue retains its independent alias requirements
1658
+ for core and browser. Query and fragment suffixes are excluded from destination calculation
1659
+ without decoding their text. Thus application Vue's `../browser?x` reaches an allowed face, while
1660
+ published Vue's matching relative import still requires the browser alias.
1661
+
1662
+ The existing alias, Node, server, absolute-path, URL, backslash, dot-segment, traversal-spelling,
1663
+ and compiler-API restrictions keep their original specifier matching. Consequently a same-face
1664
+ directory named `server` can still be refused, as can a published Vue directory named `core` or
1665
+ `browser`. Computed imports remain admitted by this boundary rule. Template-literal targets,
1666
+ `TSImportType`, CommonJS resolution, symlinks, URI decoding, and custom resolver remapping are
1667
+ outside its destination claim. POSIX, drive-letter, and UNC helper cases assert lexical behaviour;
1668
+ they do not establish a binary run on another operating system.
1669
+
1670
+ The exact direct folder `app/vue/composables` joins the function-domain register. Its camelCase
1671
+ modules require one named exported function matching the filename. Nested folders, published Vue
1672
+ composables, look-alike names, and the existing structural filename exclusions gain no registration.
1673
+ Every parser-admitted Vue case in `tests/config.test.ts` requires a debugger collection sentinel;
1674
+ a valid composable keeps that sentinel inside its exported function. Parser-refused inputs retain
1675
+ their original text, but require an exact native message, error severity, normalized filename, and
1676
+ source-token label instead of claiming debugger or policy visitation. Both contracts use the same
1677
+ native-linter acquisition helper in `tests/setupPolicy.ts`; the rule reader still refuses missing
1678
+ rule codes or filenames. Scratch controls suppress only the new report, restore only the removed
1679
+ relative regex alternatives, or remove only the Vue composable row.
1680
+
1626
1681
  The skill sweep reads named value and type imports from `@orkestrel/*` in every Markdown fence
1627
1682
  in `SKILL.md` and its named references, including fences inside lists and blockquotes. It resolves
1628
1683
  each entry through that package's exports map — the workspace's own manifest for the package the
@@ -2004,7 +2059,7 @@ succeed without making requests; remote hooks run setup. Claude Code Cloud conti
2004
2059
  the `.claude/AGENTS.md` Claude Code bridge, the `.agents/orchestration.md` agent-operation contract,
2005
2060
  the rules under `.claude/rules/` and `.cursor/rules/`, the skills under `.agents/skills/` and
2006
2061
  `.claude/skills/`, the templates under `.agents/templates/`, the transport contracts under
2007
- `.agents/transports/`, the agent roles under `.claude/agents/` and `.codex/agents/`, the
2062
+ `.agents/transports/`, the platform pages under `.agents/platforms/`, the agent roles under `.claude/agents/` and `.codex/agents/`, the
2008
2063
  `.codex/config.toml` bench configuration, and the `.mcp.json` and `.cursor/mcp.json` server
2009
2064
  registrations. A release stages every one of them, and a target receives a copy only where the plan
2010
2065
  claims the path. At the `AGENTS.md` destination it receives the pointer: different content at the