@orkestrel/scaffold 0.0.39 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/main.js +8 -1
- package/dist/bin/main.js.map +1 -1
- package/dist/host/AGENTS.md +2 -2
- package/dist/host/agents/orchestration.md +33 -2
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +16 -16
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +3 -3
- package/dist/host/agents/skills/orkestrel-align-packages/references/integration.md +1 -1
- package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +7 -2
- package/dist/host/claude/agents/builder.md +2 -2
- package/dist/host/claude/agents/orkestrel.md +48 -48
- package/dist/host/claude/rules/application.md +6 -4
- package/dist/host/claude/rules/architecture.md +2 -0
- package/dist/host/claude/rules/documentation.md +6 -0
- package/dist/host/claude/rules/tests.md +11 -1
- package/dist/host/claude/rules/typescript.md +15 -1
- package/dist/host/claude/rules/workspace.md +43 -13
- package/dist/host/claude/rules/writing.md +125 -0
- package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +10 -1
- package/dist/host/claude/skills/orkestrel-align-packages/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-build-application/SKILL.md +1 -1
- package/dist/host/claude/skills/orkestrel-harden-package/SKILL.md +1 -1
- package/dist/host/configs/policy.ts +185 -0
- package/dist/host/dotfiles/oxlintrc.json +13 -1
- package/dist/host/dotfiles/prettierignore +3 -0
- package/dist/host/guides/scaffold.md +13 -7
- package/dist/host/manifest.json +11 -7
- package/dist/host/tests/config.test.ts +195 -4
- package/dist/host/tests/policy.test.ts +82 -0
- package/dist/host/tests/setupPolicy.ts +863 -21
- package/dist/src/core/index.cjs +68 -6
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +11 -9
- package/dist/src/core/index.d.ts +11 -9
- package/dist/src/core/index.js +68 -6
- package/dist/src/core/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/host/agents/skills/orkestrel-build-application/references/application.md +0 -129
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Part of the `enterprise-bootstrap` package. Bootstrap **5.3.x**.
|
|
4
4
|
> Component markup lookups: [components.md](components.md). Utility classes: [utilities.md](utilities.md).
|
|
5
|
-
> This file holds what those
|
|
5
|
+
> This file holds what those do not: setup, color modes, theming/tokens, forms in
|
|
6
6
|
> production, the JS lifecycle, accessibility depth, and enterprise app patterns.
|
|
7
7
|
|
|
8
8
|
## Contents
|
|
@@ -99,7 +99,7 @@ The 5.3 color-mode system replaces the old per-component dark variants.
|
|
|
99
99
|
|
|
100
100
|
### Theme toggle
|
|
101
101
|
|
|
102
|
-
Bootstrap ships **no** mode picker — you build the toggle. The essentials: read the stored preference, fall back to `prefers-color-scheme`, set `data-bs-theme` on `document.documentElement`, and do it in a script early in `<head>` so the first paint
|
|
102
|
+
Bootstrap ships **no** mode picker — you build the toggle. The essentials: read the stored preference, fall back to `prefers-color-scheme`, set `data-bs-theme` on `document.documentElement`, and do it in a script early in `<head>` so the first paint does not flash the wrong mode.
|
|
103
103
|
|
|
104
104
|
```js
|
|
105
105
|
const stored = localStorage.getItem('theme')
|
|
@@ -211,7 +211,7 @@ Remove with `map-remove($utilities, "width")` or set the key to `null`. This is
|
|
|
211
211
|
|
|
212
212
|
- **Top-aligned labels by default** — the evidence (eye-tracking form research) shows fastest completion and the cleanest single-column scan, and they survive narrow screens without reflow. Reserve left-aligned labels for dense read-back forms where vertical compression matters more than speed.
|
|
213
213
|
- Visible label or `.form-floating` — never placeholder-only (disappears on input, fails accessibility).
|
|
214
|
-
- **
|
|
214
|
+
- **Do not say the same thing twice.** When the host already names the request — a card heading, a dialog title, a section header stating the question — the form associates with that name via `aria-labelledby` instead of repeating the prompt in its own label. Repetition reads as two different questions to a screen-reader user and as clutter to everyone else.
|
|
215
215
|
- One column beats multi-column for completion; use the form grid (`row g-3` + `col-md-*`) only for genuinely paired fields (city/state/zip).
|
|
216
216
|
|
|
217
217
|
```html
|
|
@@ -235,9 +235,9 @@ Remove with `map-remove($utilities, "width")` or set the key to `null`. This is
|
|
|
235
235
|
|
|
236
236
|
- Validate a field **on blur** — after the user leaves it — never on every keystroke, and never before the user has reached the field. Exception: live feedback that _helps_ while typing (password strength, username availability, character counts).
|
|
237
237
|
- Once a field is in an error state, re-validate as the user types so they see the fix land.
|
|
238
|
-
- Always re-check everything on submit. Keep the submit button **enabled** — a disabled submit hides _what
|
|
238
|
+
- Always re-check everything on submit. Keep the submit button **enabled** — a disabled submit hides _what is_ wrong; a validating submit shows it.
|
|
239
239
|
- On failed submit of a long form, render an **error summary** at the top (focus it; link each item to its field) _and_ inline messages at each field — never summary-only, never inline-only.
|
|
240
|
-
- Error style = color + icon + text, stating what
|
|
240
|
+
- Error style = color + icon + text, stating what is wrong and how to fix it. Wire message to field with `aria-describedby`, mark the field `aria-invalid="true"`. Never report errors via tooltip-on-hover.
|
|
241
241
|
|
|
242
242
|
### Bootstrap validation mechanics
|
|
243
243
|
|
|
@@ -329,7 +329,7 @@ el.addEventListener('hidden.bs.modal', () => {
|
|
|
329
329
|
|
|
330
330
|
### Popper
|
|
331
331
|
|
|
332
|
-
Dropdowns, tooltips, and popovers require Popper — load `bootstrap.bundle.min.js` (includes it) or `@popperjs/core` before `bootstrap.min.js`. Modal, collapse, offcanvas, toast, tab, alert
|
|
332
|
+
Dropdowns, tooltips, and popovers require Popper — load `bootstrap.bundle.min.js` (includes it) or `@popperjs/core` before `bootstrap.min.js`. Modal, collapse, offcanvas, toast, tab, alert do not need it.
|
|
333
333
|
|
|
334
334
|
## Accessibility
|
|
335
335
|
|
|
@@ -364,15 +364,15 @@ Wire the reader into the suite once it has settled a question.
|
|
|
364
364
|
- **Focus not obscured (2.4.11, AA).** Sticky headers/footers/action bars and toast overlays must not bury the focused element. Reserve space with `scroll-margin-top` on focusables (or `scroll-padding-top` on the scroll container) equal to the sticky chrome height.
|
|
365
365
|
- **Dragging alternatives (2.5.7, AA).** Any drag (row reorder, kanban, slider, resize) needs a non-drag single-pointer path: move up/down buttons, numeric input, click-to-place.
|
|
366
366
|
- **Accessible authentication (3.3.8, AA).** Never block paste in password/OTP fields; support password managers; no puzzle as the only way in.
|
|
367
|
-
- **Redundant entry (3.3.7, A).**
|
|
367
|
+
- **Redundant entry (3.3.7, A).** Do not ask for the same information twice in one flow — auto-fill or offer "same as above". Governs wizards directly.
|
|
368
368
|
- **Consistent help (3.2.6, A).** If a help affordance repeats across pages, keep it in the same relative place everywhere.
|
|
369
369
|
- Housekeeping: SC 4.1.1 Parsing was removed in 2.2 — duplicate-ID lint is no longer a WCAG failure by itself (still fix it).
|
|
370
370
|
|
|
371
371
|
### Pattern contracts (APG, compact)
|
|
372
372
|
|
|
373
|
-
- **Dialog/modal:** `role="dialog"` (`alertdialog` for destructive confirms) + `aria-modal="true"` + `aria-labelledby`. Focus moves in on open, Tab is trapped, Esc closes, focus returns to the invoker. Bootstrap's modal does this — verify you
|
|
373
|
+
- **Dialog/modal:** `role="dialog"` (`alertdialog` for destructive confirms) + `aria-modal="true"` + `aria-labelledby`. Focus moves in on open, Tab is trapped, Esc closes, focus returns to the invoker. Bootstrap's modal does this — verify you did not break focus-return by removing the trigger.
|
|
374
374
|
- **Tabs:** `tablist` > `tab` (+`aria-selected`, `aria-controls`) with panels `tabpanel`. Roving tabindex: Left/Right between tabs, Home/End to ends; only the selected tab is `tabindex="0"`.
|
|
375
|
-
- **Disclosure:** a `<button>` with `aria-expanded` + `aria-controls`. Enter/Space toggles. That
|
|
375
|
+
- **Disclosure:** a `<button>` with `aria-expanded` + `aria-controls`. Enter/Space toggles. That is the whole contract — Bootstrap collapse matches it.
|
|
376
376
|
- **Radio group:** prefer native `<input type="radio" name>` — one tab stop and arrow-selection come free.
|
|
377
377
|
- **Combobox:** input `role="combobox"` + `aria-expanded` + `aria-controls` + `aria-activedescendant` tracking the active option; Down opens/advances, Enter accepts, Esc closes. This is the hardest contract on the list — see [When not to hand-roll](#when-not-to-hand-roll).
|
|
378
378
|
- **Toolbar:** `role="toolbar"` + `aria-label`; one tab stop, arrows move between controls (roving tabindex). Use it to collapse a dense button cluster's tab-stops.
|
|
@@ -389,7 +389,7 @@ Browsers handle focus on full page loads; in an SPA **you** do:
|
|
|
389
389
|
|
|
390
390
|
### Reduced motion
|
|
391
391
|
|
|
392
|
-
Bootstrap wraps its transitions and animations (`.fade`, `.collapsing`, carousel slide, spinner speed) in `prefers-reduced-motion: reduce` handling — transitions are disabled or slowed automatically when `$enable-reduced-motion` is on (default). Your obligations: wrap **custom** animation in `@media (prefers-reduced-motion: no-preference)`,
|
|
392
|
+
Bootstrap wraps its transitions and animations (`.fade`, `.collapsing`, carousel slide, spinner speed) in `prefers-reduced-motion: reduce` handling — transitions are disabled or slowed automatically when `$enable-reduced-motion` is on (default). Your obligations: wrap **custom** animation in `@media (prefers-reduced-motion: no-preference)`, do not auto-play movement for reduced-motion users, and keep any purely decorative motion cuttable.
|
|
393
393
|
|
|
394
394
|
## Enterprise Patterns
|
|
395
395
|
|
|
@@ -457,7 +457,7 @@ The Bootstrap implementation — a responsive offcanvas that renders inline abov
|
|
|
457
457
|
|
|
458
458
|
**Navigation rules:**
|
|
459
459
|
|
|
460
|
-
- Breadcrumbs only for genuinely hierarchical models (org → account → contact); in flat or tabbed apps they
|
|
460
|
+
- Breadcrumbs only for genuinely hierarchical models (org → account → contact); in flat or tabbed apps they are noise. Current item: `aria-current="page"`, not a link.
|
|
461
461
|
- A command palette (Ctrl/Cmd-K) is an accelerator **on top of** visible nav, never a replacement — everything it exposes needs a discoverable UI route too.
|
|
462
462
|
- Keyboard shortcuts: use conventional bindings (Ctrl/Cmd-K palette, `/` focuses search, `?` opens the shortcut cheat-sheet), surface them in tooltips, and never let single-key shortcuts fire while an input has focus.
|
|
463
463
|
- Dashboard composition follows the same craft as any screen: state the screen's single job, lead with the numbers that answer it, and keep every widget to one job — a dashboard is not a place to exhibit every chart type.
|
|
@@ -469,7 +469,7 @@ The Bootstrap implementation — a responsive offcanvas that renders inline abov
|
|
|
469
469
|
**Craft rules:**
|
|
470
470
|
|
|
471
471
|
- **Align by type:** numbers, currency, dates right-aligned (`text-end`, header too); text left. Use tabular figures so digits stack into comparable columns: `font-variant-numeric: tabular-nums` on numeric cells (one small custom rule that earns its place).
|
|
472
|
-
- **Density:** `table-sm` for compact; offer density as a user toggle (comfortable/compact) driven by one token or wrapper class, not per-cell tweaks.
|
|
472
|
+
- **Density:** `table-sm` for compact; offer density as a user toggle (comfortable/compact) driven by one token or wrapper class, not per-cell tweaks. Do not shrink font below readability to fake density.
|
|
473
473
|
- **Sticky header** once the table meaningfully scrolls (roughly a viewport / ~15+ rows). Not built into Bootstrap — the pattern:
|
|
474
474
|
|
|
475
475
|
```html
|
|
@@ -508,7 +508,7 @@ Give header cells an **opaque background** (`bg-body-secondary` or a table varia
|
|
|
508
508
|
- One toolbar above the table: search input first (`role="search"` on the form), then the 2–4 highest-value filters as `form-select`/segmented controls, overflow filters behind a "Filters" button (offcanvas on mobile, dropdown/collapse on desktop).
|
|
509
509
|
- **Active filters must be visible and dismissible** — chips/badges with an ✕ and a "Clear all" — users must see _why_ the list is short. A filtered-empty state repeats the escape hatch.
|
|
510
510
|
- Debounce live search; show result counts ("128 results") so feedback is immediate; filter state belongs in the URL when views are shareable.
|
|
511
|
-
- Toolbars that overflow: `flex-nowrap overflow-auto` beats wrapping into a two-row toolbar mid-task —
|
|
511
|
+
- Toolbars that overflow: `flex-nowrap overflow-auto` beats wrapping into a two-row toolbar mid-task — do not crush icon targets below 24px.
|
|
512
512
|
|
|
513
513
|
### Wizards & multi-step forms
|
|
514
514
|
|
|
@@ -520,10 +520,10 @@ Give header cells an **opaque background** (`bg-body-secondary` or a table varia
|
|
|
520
520
|
|
|
521
521
|
### The five states
|
|
522
522
|
|
|
523
|
-
Design **all five** for every data surface: ideal (populated), empty, loading, partial, error. A component
|
|
523
|
+
Design **all five** for every data surface: ideal (populated), empty, loading, partial, error. A component is not done until all five exist.
|
|
524
524
|
|
|
525
525
|
- **Skeleton vs spinner:** skeleton (`placeholder` + `placeholder-glow`) when you know the content's shape and it fills a region — tables, cards, detail panes — because it holds layout and shortens perceived wait. Spinner for short, indeterminate, or in-control waits (inside a button, a small inline fetch).
|
|
526
|
-
- **Thresholds (guidance):** under ~1s show nothing — a flashed loader is worse than none; ~1–10s show a spinner or skeleton; beyond ~10s show determinate progress (percent or step) so it
|
|
526
|
+
- **Thresholds (guidance):** under ~1s show nothing — a flashed loader is worse than none; ~1–10s show a spinner or skeleton; beyond ~10s show determinate progress (percent or step) so it does not feel hung.
|
|
527
527
|
- **Optimistic vs pessimistic:** apply UI immediately and reconcile (rolling back loudly on failure) for reversible high-frequency actions — toggles, stars, reorders. Await confirmation for money, audited records, and anything a rollback would confuse.
|
|
528
528
|
- **Empty states** invite the next action (button + one line of why). Never-had-data and filtered-empty are different states with different escapes — never ship one generic "nothing here".
|
|
529
529
|
- **Every error state states what failed and how to fix it**, carries a keyboard-reachable retry in place, and preserves surrounding context — a body fetch failure must not blow away the toolbar and filters.
|
|
@@ -547,7 +547,7 @@ Match friction to reversibility × blast radius:
|
|
|
547
547
|
2. **Confirm dialog** for irreversible-but-scoped operations. Restate the specific consequence ("This permanently deletes 3 invoices"), verb-labeled buttons ("Delete invoices" / "Cancel" — never Yes/No), destructive action visually separated from safe; `alertdialog` semantics; focus lands on the safe action.
|
|
548
548
|
3. **Type-to-confirm** (type the entity name) only for high-blast-radius irreversible operations — delete an org, drop a dataset.
|
|
549
549
|
|
|
550
|
-
|
|
550
|
+
Do not type-gate a single-row delete; do not one-tap a tenant wipe. Confirm only where this ladder calls for it — a confirmation on every action gets clicked through.
|
|
551
551
|
|
|
552
552
|
**Neutralize a disabled destructive control.** `btn-danger` at full saturation reads as armed whatever the `disabled` attribute says, and the contrast exemption for disabled controls does not excuse it. While the action is unavailable, drop to the neutral or outline variant (or let the disabled state mute the fill) so the color stops promising an action, and say _why_ it is unavailable in text the assistive layer reaches: `aria-describedby` pointing at the reason, with `title` only as the pointer-user convenience on top. Never use `title` alone — it never reaches a keyboard or screen-reader user, and it disappears on touch.
|
|
553
553
|
|
|
@@ -400,7 +400,7 @@ Multiple targets: give each panel `.multi-collapse` and point separate triggers
|
|
|
400
400
|
</ul>
|
|
401
401
|
```
|
|
402
402
|
|
|
403
|
-
(The `list-group-checkable` / `list-group-item-check` classes seen in Bootstrap's _examples gallery_ are custom CSS, not core —
|
|
403
|
+
(The `list-group-checkable` / `list-group-item-check` classes seen in Bootstrap's _examples gallery_ are custom CSS, not core — do not ship them without their styles.)
|
|
404
404
|
|
|
405
405
|
### Modal
|
|
406
406
|
|
|
@@ -625,7 +625,7 @@ Real switchable tab panels (JS-driven — buttons, not scroll anchors):
|
|
|
625
625
|
</div>
|
|
626
626
|
```
|
|
627
627
|
|
|
628
|
-
**Responsive offcanvas** — the canonical sidebar-that-becomes-a-drawer: replace `.offcanvas` with `.offcanvas-{sm|md|lg|xl|xxl}`. Content renders **inline above** that breakpoint and as an **offcanvas below** it. Close buttons inside a responsive offcanvas need an explicit `data-bs-target`. Always set `aria-labelledby` (it
|
|
628
|
+
**Responsive offcanvas** — the canonical sidebar-that-becomes-a-drawer: replace `.offcanvas` with `.offcanvas-{sm|md|lg|xl|xxl}`. Content renders **inline above** that breakpoint and as an **offcanvas below** it. Close buttons inside a responsive offcanvas need an explicit `data-bs-target`. Always set `aria-labelledby` (it is conceptually a dialog; `role="dialog"` is added by JS). Width/height via `--bs-offcanvas-width` (400px) / `--bs-offcanvas-height` (30vh). Full app-shell pattern: [bootstrap-reference.md](bootstrap-reference.md) → App shell.
|
|
629
629
|
|
|
630
630
|
### Pagination
|
|
631
631
|
|
|
@@ -1012,7 +1012,7 @@ Exactly one item in a selection carries `aria-current` — the visual fill and t
|
|
|
1012
1012
|
### Navigation & overlays
|
|
1013
1013
|
|
|
1014
1014
|
- Active nav items need `aria-current="page"` (or `aria-selected="true"` for tabs).
|
|
1015
|
-
- Modals and offcanvas: set `aria-labelledby`; Bootstrap traps focus and restores it on close —
|
|
1015
|
+
- Modals and offcanvas: set `aria-labelledby`; Bootstrap traps focus and restores it on close — do not fight it; `dispose()` instances when the host unmounts in SPAs.
|
|
1016
1016
|
- Icon-only controls always need an accessible name (`aria-label` or visually-hidden text) and a ≥24px target.
|
|
1017
1017
|
|
|
1018
1018
|
### Theming
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Map ownership
|
|
4
4
|
|
|
5
|
-
Dependency direction across environments is the root project model in `AGENTS.md`, detailed for placement in `.claude/rules/workspace.md` and for app composition in `.claude/rules/application.md`. Read those; this reference does not restate them. Apply the same law to a dependency's `@orkestrel/<package>/browser` and `/server` exports
|
|
5
|
+
Dependency direction across environments is the root project model in `AGENTS.md`, detailed for placement in `.claude/rules/workspace.md` and for app composition in `.claude/rules/application.md`. Read those; this reference does not restate them. Apply the same law to a dependency's `@orkestrel/<package>/browser` and `/server` exports.
|
|
6
6
|
|
|
7
7
|
Ownership across packages is what those rules leave open: framework packages own reusable mechanisms, and applications own workflows, policy, presentation, users, authorization decisions, and product-specific defaults.
|
|
8
8
|
|
|
@@ -69,11 +69,16 @@ includes app/core so the shared transport contracts have one host-independent ow
|
|
|
69
69
|
template-literal specifiers, declaration placement, and the barrel law.
|
|
70
70
|
- Scoped TypeScript projects — host-global isolation.
|
|
71
71
|
- Vite's real builds and environment-boundary plugin — Vue, CSS, assets, workers,
|
|
72
|
-
runtime resolution, and physical workspace containment.
|
|
72
|
+
runtime resolution, and physical workspace containment. Its parsed HTML asset
|
|
73
|
+
callbacks reject forced inlining before any direct asset read, and non-inlined
|
|
74
|
+
output assets are audited by physical source path.
|
|
73
75
|
|
|
74
76
|
Then hold these four limits:
|
|
75
77
|
- Add no standalone boundary script, and no second parser or source-language analyzer
|
|
76
|
-
duplicating those layers.
|
|
78
|
+
duplicating those layers. Reach for the toolchain's own facilities instead: Vite's
|
|
79
|
+
Oxc/Rolldown AST for TypeScript and JavaScript asset references, the official Vue SFC
|
|
80
|
+
compiler for `.vue` blocks, Vite's HTML parser callbacks, its bundled Lightning CSS
|
|
81
|
+
dependency analyzer, and the TypeScript compiler API for the narrow coding-law pass.
|
|
77
82
|
- Disable the browser application's public directory, so an unmanaged file copy cannot
|
|
78
83
|
bypass the module graph.
|
|
79
84
|
- Keep browser-only runtime tooling development-only.
|
|
@@ -29,10 +29,10 @@ You are an Executor: do the work yourself, spawn nothing.
|
|
|
29
29
|
- No mocks, behavioral fakes, superfluous wrappers, or current-scope
|
|
30
30
|
TODOs/skips/deferrals.
|
|
31
31
|
|
|
32
|
-
## Deviation protocol — stop,
|
|
32
|
+
## Deviation protocol — stop, do not solve
|
|
33
33
|
|
|
34
34
|
The moment reality diverges from the dispatch — an unexpected error, a file that
|
|
35
|
-
|
|
35
|
+
is not what the plan says, a failing assumption, a scope surprise — STOP that line of
|
|
36
36
|
work and return a **deviation report**:
|
|
37
37
|
|
|
38
38
|
- **Expected** — what the dispatch said.
|
|
@@ -34,54 +34,54 @@ so network-controlled descriptions never enter agent instruction context.
|
|
|
34
34
|
|
|
35
35
|
<!-- orkestrel:catalog -->
|
|
36
36
|
|
|
37
|
-
| Package | Version | Layer | Runtime dependencies
|
|
38
|
-
| ----------------------- | -------- | ----- |
|
|
39
|
-
| `@orkestrel/abort` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
40
|
-
| `@orkestrel/agent` | `0.0.
|
|
41
|
-
| `@orkestrel/brief` | `0.0.
|
|
42
|
-
| `@orkestrel/browser` | `0.0.
|
|
43
|
-
| `@orkestrel/budget` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
44
|
-
| `@orkestrel/console` | `0.0.8` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
45
|
-
| `@orkestrel/contract` | `0.0.12` | L0 |
|
|
46
|
-
| `@orkestrel/csv` | `0.0.4` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
47
|
-
| `@orkestrel/database` | `0.0.10` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/indexeddb` `^0.0.8`, `@orkestrel/sqlite` `^0.0.8`
|
|
48
|
-
| `@orkestrel/emitter` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
49
|
-
| `@orkestrel/form` | `0.0.2` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
50
|
-
| `@orkestrel/guide` | `0.0.
|
|
51
|
-
| `@orkestrel/html` | `0.0.4` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
52
|
-
| `@orkestrel/indexeddb` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
53
|
-
| `@orkestrel/interpret` | `0.0.
|
|
54
|
-
| `@orkestrel/markdown` | `0.0.9` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/html` `^0.0.4`
|
|
55
|
-
| `@orkestrel/mcp` | `0.0.
|
|
56
|
-
| `@orkestrel/middleware` | `0.0.
|
|
57
|
-
| `@orkestrel/msg` | `0.0.7` | L0 |
|
|
58
|
-
| `@orkestrel/ndjson` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
59
|
-
| `@orkestrel/ollama` | `0.0.
|
|
60
|
-
| `@orkestrel/pool` | `0.0.8` | L2 | `@orkestrel/emitter` `^0.0.7`
|
|
61
|
-
| `@orkestrel/program` | `0.0.
|
|
62
|
-
| `@orkestrel/qualifier` | `0.0.
|
|
63
|
-
| `@orkestrel/queue` | `0.0.
|
|
64
|
-
| `@orkestrel/rater` | `0.0.
|
|
65
|
-
| `@orkestrel/reason` | `0.0.7` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
66
|
-
| `@orkestrel/relation` | `0.0.
|
|
67
|
-
| `@orkestrel/router` | `0.0.10` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
68
|
-
| `@orkestrel/scaffold` | `0.0.
|
|
69
|
-
| `@orkestrel/sea` | `0.0.7` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
70
|
-
| `@orkestrel/server` | `0.0.
|
|
71
|
-
| `@orkestrel/sqlite` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
72
|
-
| `@orkestrel/sse` | `0.0.5` | L0 |
|
|
73
|
-
| `@orkestrel/supervisor` | `0.0.1` | L5 | `@orkestrel/contract` `^0.0.11`, `@orkestrel/database` `^0.0.9`, `@orkestrel/emitter` `^0.0.6`, `@orkestrel/workflow` `^0.0.12`
|
|
74
|
-
| `@orkestrel/table` | `0.0.2` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
75
|
-
| `@orkestrel/template` | `0.0.4` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`
|
|
76
|
-
| `@orkestrel/terminal` | `0.0.
|
|
77
|
-
| `@orkestrel/test` | `0.0.6` | L0 |
|
|
78
|
-
| `@orkestrel/timeout` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
79
|
-
| `@orkestrel/tool` | `0.0.11` | L1 | `@orkestrel/contract` `^0.0.12`
|
|
80
|
-
| `@orkestrel/toolbox` | `0.0.
|
|
81
|
-
| `@orkestrel/websocket` | `0.0.9` | L2 | `@orkestrel/emitter` `^0.0.7`
|
|
82
|
-
| `@orkestrel/worker` | `0.0.
|
|
83
|
-
| `@orkestrel/workflow` | `0.0.
|
|
84
|
-
| `@orkestrel/workspace` | `0.0.
|
|
37
|
+
| Package | Version | Layer | Runtime dependencies |
|
|
38
|
+
| ----------------------- | -------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| `@orkestrel/abort` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
40
|
+
| `@orkestrel/agent` | `0.0.16` | L5 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/queue` `^0.0.9`, `@orkestrel/timeout` `^0.0.7`, `@orkestrel/tool` `^0.0.11`, `@orkestrel/workflow` `^0.0.13`, `@orkestrel/workspace` `^0.0.5` |
|
|
41
|
+
| `@orkestrel/brief` | `0.0.3` | L4 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/interpret` `^0.0.10`, `@orkestrel/reason` `^0.0.7` |
|
|
42
|
+
| `@orkestrel/browser` | `0.0.10` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/html` `^0.0.4`, `@orkestrel/websocket` `^0.0.9` |
|
|
43
|
+
| `@orkestrel/budget` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
44
|
+
| `@orkestrel/console` | `0.0.8` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
45
|
+
| `@orkestrel/contract` | `0.0.12` | L0 | |
|
|
46
|
+
| `@orkestrel/csv` | `0.0.4` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
47
|
+
| `@orkestrel/database` | `0.0.10` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/indexeddb` `^0.0.8`, `@orkestrel/sqlite` `^0.0.8` |
|
|
48
|
+
| `@orkestrel/emitter` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
49
|
+
| `@orkestrel/form` | `0.0.2` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
50
|
+
| `@orkestrel/guide` | `0.0.12` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/markdown` `^0.0.9` |
|
|
51
|
+
| `@orkestrel/html` | `0.0.4` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
52
|
+
| `@orkestrel/indexeddb` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
53
|
+
| `@orkestrel/interpret` | `0.0.10` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/reason` `^0.0.7`, `@orkestrel/template` `^0.0.4` |
|
|
54
|
+
| `@orkestrel/markdown` | `0.0.9` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/html` `^0.0.4` |
|
|
55
|
+
| `@orkestrel/mcp` | `0.0.17` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/sse` `^0.0.5`, `@orkestrel/tool` `^0.0.11`, `@orkestrel/websocket` `^0.0.9` |
|
|
56
|
+
| `@orkestrel/middleware` | `0.0.14` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/timeout` `^0.0.7` |
|
|
57
|
+
| `@orkestrel/msg` | `0.0.7` | L0 | |
|
|
58
|
+
| `@orkestrel/ndjson` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
59
|
+
| `@orkestrel/ollama` | `0.0.10` | L6 | `@orkestrel/agent` `^0.0.16`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/ndjson` `^0.0.7`, `@orkestrel/timeout` `^0.0.7`, `@orkestrel/tool` `^0.0.11` |
|
|
60
|
+
| `@orkestrel/pool` | `0.0.8` | L2 | `@orkestrel/emitter` `^0.0.7` |
|
|
61
|
+
| `@orkestrel/program` | `0.0.9` | L4 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/qualifier` `^0.0.10`, `@orkestrel/rater` `^0.0.11`, `@orkestrel/reason` `^0.0.7` |
|
|
62
|
+
| `@orkestrel/qualifier` | `0.0.10` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/reason` `^0.0.7` |
|
|
63
|
+
| `@orkestrel/queue` | `0.0.9` | L3 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/timeout` `^0.0.7` |
|
|
64
|
+
| `@orkestrel/rater` | `0.0.11` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/reason` `^0.0.7` |
|
|
65
|
+
| `@orkestrel/reason` | `0.0.7` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
66
|
+
| `@orkestrel/relation` | `0.0.9` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7` |
|
|
67
|
+
| `@orkestrel/router` | `0.0.10` | L2 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
68
|
+
| `@orkestrel/scaffold` | `0.0.40` | L3 | `@orkestrel/console` `^0.0.8`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/markdown` `^0.0.9`, `@orkestrel/template` `^0.0.4` |
|
|
69
|
+
| `@orkestrel/sea` | `0.0.7` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
70
|
+
| `@orkestrel/server` | `0.0.13` | L3 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/router` `^0.0.10`, `@orkestrel/timeout` `^0.0.7` |
|
|
71
|
+
| `@orkestrel/sqlite` | `0.0.8` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
72
|
+
| `@orkestrel/sse` | `0.0.5` | L0 | |
|
|
73
|
+
| `@orkestrel/supervisor` | `0.0.1` | L5 | `@orkestrel/contract` `^0.0.11`, `@orkestrel/database` `^0.0.9`, `@orkestrel/emitter` `^0.0.6`, `@orkestrel/workflow` `^0.0.12` |
|
|
74
|
+
| `@orkestrel/table` | `0.0.2` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
75
|
+
| `@orkestrel/template` | `0.0.4` | L2 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/emitter` `^0.0.7` |
|
|
76
|
+
| `@orkestrel/terminal` | `0.0.10` | L3 | `@orkestrel/console` `^0.0.8`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/form` `^0.0.2`, `@orkestrel/sse` `^0.0.5` |
|
|
77
|
+
| `@orkestrel/test` | `0.0.6` | L0 | |
|
|
78
|
+
| `@orkestrel/timeout` | `0.0.7` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
79
|
+
| `@orkestrel/tool` | `0.0.11` | L1 | `@orkestrel/contract` `^0.0.12` |
|
|
80
|
+
| `@orkestrel/toolbox` | `0.0.7` | L6 | `@orkestrel/agent` `^0.0.16`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/form` `^0.0.2`, `@orkestrel/relation` `^0.0.9`, `@orkestrel/server` `^0.0.13`, `@orkestrel/terminal` `^0.0.10`, `@orkestrel/tool` `^0.0.11`, `@orkestrel/workflow` `^0.0.13`, `@orkestrel/workspace` `^0.0.5` |
|
|
81
|
+
| `@orkestrel/websocket` | `0.0.9` | L2 | `@orkestrel/emitter` `^0.0.7` |
|
|
82
|
+
| `@orkestrel/worker` | `0.0.8` | L4 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/pool` `^0.0.8`, `@orkestrel/queue` `^0.0.9` |
|
|
83
|
+
| `@orkestrel/workflow` | `0.0.13` | L4 | `@orkestrel/abort` `^0.0.7`, `@orkestrel/budget` `^0.0.7`, `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7`, `@orkestrel/queue` `^0.0.9`, `@orkestrel/timeout` `^0.0.7` |
|
|
84
|
+
| `@orkestrel/workspace` | `0.0.5` | L3 | `@orkestrel/contract` `^0.0.12`, `@orkestrel/database` `^0.0.10`, `@orkestrel/emitter` `^0.0.7` |
|
|
85
85
|
|
|
86
86
|
<!-- /orkestrel:catalog -->
|
|
87
87
|
|
|
@@ -41,10 +41,12 @@ paths:
|
|
|
41
41
|
- Published `src` environments never import private `app` modules. Src core is
|
|
42
42
|
host-independent; src browser/server may import src core but never one
|
|
43
43
|
another's implementation. Apply the same environment law to
|
|
44
|
-
`@orkestrel/<package>/browser` and `/server` exports
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
`@orkestrel/<package>/browser` and `/server` exports; a package's bare export
|
|
45
|
+
is its core API.
|
|
46
|
+
- App-only manifests are unscoped and `private: true`, with no `main`,
|
|
47
|
+
`module`, `types`, export map, or publish configuration. Mixed manifests
|
|
48
|
+
publish only `dist/src`, and Vue remains development-only because app output
|
|
49
|
+
is never published.
|
|
48
50
|
- Give app/server process signals to a tested, explicitly stoppable,
|
|
49
51
|
generation-safe runner whose stale failures cannot release a newer run.
|
|
50
52
|
- Return the runner from convenience startup, so normal cleanup cannot be hidden.
|
|
@@ -104,6 +104,8 @@ kind. It reads declaration syntax and file name, never meaning.
|
|
|
104
104
|
data-kind file, that every centralized declaration is exported, that a class sits in its matching
|
|
105
105
|
implementation or errors file, and that `constants.ts` declares only UPPER_SNAKE_CASE consts with
|
|
106
106
|
no bare collection literal.
|
|
107
|
+
- It proves that no source, test, config, or script file carries an `eslint-disable` or
|
|
108
|
+
`oxlint-disable` directive.
|
|
107
109
|
- It does not prove a collection is frozen. It reads the declaration, never the value a call
|
|
108
110
|
returns, so `Object.freeze([…])` and any other call initializer are one syntax to it. The freeze
|
|
109
111
|
obligation in the kind-purity rules above binds regardless; only the bare literal is mechanical.
|
|
@@ -63,10 +63,16 @@ Never use in-repository `@src/*` aliases in public guide examples; reserve them
|
|
|
63
63
|
|
|
64
64
|
- Skills prescribe reusable process; they do not copy naming, placement, syntax, lifecycle, or test laws from `AGENTS.md` and rules.
|
|
65
65
|
- Keep `SKILL.md` concise and route conditional detail to one-level `references/`.
|
|
66
|
+
- Name every Markdown file in a skill's `references/` from its `SKILL.md`, and delete a reference nothing names.
|
|
66
67
|
- Frontmatter contains only `name` and a trigger-focused `description`.
|
|
68
|
+
- Set `name` to the skill's own directory name.
|
|
69
|
+
- Write `description` as a single-line scalar or a folded `>-` block, and no other shape. Include in it a sentence beginning `Use ` that names when to invoke the skill.
|
|
67
70
|
- Do not put model routing or package version catalogs in a skill.
|
|
68
71
|
- Validate every referenced resource; do not leave template TODOs or auxiliary README/changelog files.
|
|
69
72
|
- Write `agents/openai.yaml` as one root `interface:` mapping over exactly `display_name`, `short_description`, and `default_prompt`, in that order, each on its own two-space-indented line.
|
|
70
73
|
- Give every one of those keys a non-empty single-quoted scalar, and write an apostrophe inside it as `''`.
|
|
71
74
|
- Name the skill's own `$<directory>` token in `default_prompt`.
|
|
72
75
|
- Keep provider bridges minimal: they load one canonical workflow and add no competing instructions.
|
|
76
|
+
- Give a provider bridge its canonical skill's `name` and `description` verbatim, name the `.agents/skills/<name>/SKILL.md` path it loads, and give it no references of its own.
|
|
77
|
+
- Give every canonical skill exactly one provider bridge directory of the same name, and give every bridge directory a canonical twin.
|
|
78
|
+
- Review a bridge body's remaining instructions yourself: the policy sweep proves `name` and `description` parity, the named canonical path, and the absence of bridge-owned references, and nothing else about the body.
|
|
@@ -18,7 +18,9 @@ paths:
|
|
|
18
18
|
not add `tests/configs/`.
|
|
19
19
|
- Resolve a mirrored module through `.ts`, `.tsx`, `.mts`, `.cts`, `.vue`, `.scss`, or `.css`.
|
|
20
20
|
- Resolve a Sass or CSS partial through the module's leading underscore.
|
|
21
|
-
- Resolve
|
|
21
|
+
- Resolve each root `tests/setup*.test.ts` proof against its sibling `tests/setup*.ts` module. A
|
|
22
|
+
root `tests/setup.test.ts` file can prove several setup modules when their helpers serve
|
|
23
|
+
several projects.
|
|
22
24
|
- Prefer test filenames matching entrypoints: `index.test.ts` for `index.ts`, `main.test.ts` for `main.ts`.
|
|
23
25
|
- Tests are deterministic: identical inputs produce identical results.
|
|
24
26
|
- Keep default suites fast: timers normally use 10–50 ms and tests make no network calls.
|
|
@@ -54,8 +56,12 @@ its own:
|
|
|
54
56
|
| `tests/conformance.test.ts` | Where this package drifts from the official tooling it tracks |
|
|
55
57
|
| `tests/distribution.test.ts` | The packed package installs and resolves through its public exports |
|
|
56
58
|
| `tests/integration.test.ts` | The package's features work together end to end across environments |
|
|
59
|
+
| `tests/setup*.test.ts` | Reusable behavior exported from sibling `tests/setup*.ts` modules works as the workspace's suites require |
|
|
57
60
|
| `tests/service/**/*.test.ts` | The live external services this package drives, driven for real |
|
|
58
61
|
|
|
62
|
+
- Put each root `tests/setup*.test.ts` proof in the `setup` project. Keep its assertions on
|
|
63
|
+
exported test-infrastructure behavior: do not duplicate production behavior there, and do not
|
|
64
|
+
move setup-helper assertions into another cross-cutting proof.
|
|
59
65
|
- `.claude/rules/workspace.md` names the Vitest project each location belongs to.
|
|
60
66
|
- The `guides` project runs in Node with the browser disabled. Its subject is what the guide
|
|
61
67
|
claims: that every documented name resolves, and that every fence asserting a value returns
|
|
@@ -146,6 +152,10 @@ Test helpers are shared infrastructure, not local test-file clutter.
|
|
|
146
152
|
|
|
147
153
|
`@orkestrel/test` owns the helpers every workspace repeats: the call recorder, the real delay, the JSON and async collectors, and the owned scratch directory. Import them from `@orkestrel/test`, and its Node-only helpers from `@orkestrel/test/server`. Write a helper of your own only where the package exports none for the job. The shapes below are the contract a workspace codes against, not source to copy.
|
|
148
154
|
|
|
155
|
+
- For the vendored test set (`tests/setupPolicy.ts`, `tests/policy.test.ts`, and
|
|
156
|
+
`tests/config.test.ts`), keep shared helpers within that set instead of importing them from
|
|
157
|
+
`@orkestrel/test`; follow the vendored-file import law in `.claude/rules/workspace.md`.
|
|
158
|
+
|
|
149
159
|
- Extract a fixture, recorder, event factory, async wait, renderer, scenario/data builder, protocol fixture, or DOM builder as soon as it could serve another test.
|
|
150
160
|
- Any duplicate or near-duplicate helper is a defect; consolidate it into one general form.
|
|
151
161
|
- Export every reusable helper, fixture type, factory, constant, and guard from setup files.
|
|
@@ -17,12 +17,19 @@ The non-negotiables and design laws in `AGENTS.md` apply without exception and a
|
|
|
17
17
|
- Place `import type` declarations before value imports.
|
|
18
18
|
- Do not place blank lines between consecutive imports of the same kind.
|
|
19
19
|
- Narrow an accepted `unknown` with a total guard rather than a conditional access.
|
|
20
|
+
- A parameter property is a constructor parameter carrying any accessibility or `readonly` modifier.
|
|
21
|
+
The ban reaches every form, `readonly` alone included; declare the `#` field and assign it in the
|
|
22
|
+
constructor body.
|
|
20
23
|
|
|
21
24
|
## Types
|
|
22
25
|
|
|
23
26
|
- Put every reusable or public interface/type alias in the nearest authoritative `*/types.ts`.
|
|
24
27
|
- Public collection properties and return types use `readonly T[]`, `ReadonlyMap<K, V>`, or `ReadonlySet<T>`.
|
|
25
28
|
- Optional state is `T | undefined`; an optional lookup failure returns `undefined`.
|
|
29
|
+
- `as const` annotates a literal with its own type and never overrides the checker, so the assertion
|
|
30
|
+
ban does not reach it. Use it to derive a literal union from a value and to fix a tuple's arity and
|
|
31
|
+
element types. Do not write it on a value whose contract is already declared; annotate the
|
|
32
|
+
declaration instead.
|
|
26
33
|
|
|
27
34
|
## Immutability
|
|
28
35
|
|
|
@@ -63,8 +70,15 @@ type Result<T, E = Error> = Success<T> | Failure<E>
|
|
|
63
70
|
|
|
64
71
|
## Comments and API documentation
|
|
65
72
|
|
|
66
|
-
- Comments explain why, never restate what self-explanatory code does. The Writing rules in `AGENTS.md` govern their prose.
|
|
73
|
+
- Comments explain why, never restate what self-explanatory code does. The Writing rules in `AGENTS.md` and `.claude/rules/writing.md` govern their prose.
|
|
67
74
|
- Every public export has complete TSDoc: description, `@param`, `@returns`, and `@example` where applicable.
|
|
75
|
+
- The first sentence states what the symbol does in the third person with an `-s` verb — `Creates`,
|
|
76
|
+
`Returns`, `Checks whether` — and never repeats the symbol's name.
|
|
77
|
+
- Describe a boolean parameter as "If `true`, …; if `false`, …", and a boolean return as
|
|
78
|
+
"True if …; false otherwise".
|
|
79
|
+
- Write a default as "Default: …" and a thrown error as "Thrown when …".
|
|
80
|
+
- State a prerequisite and the failure behavior wherever the symbol has either.
|
|
81
|
+
- `@deprecated` names the replacement first, then the reason.
|
|
68
82
|
- Document an options object as one `@param`; describe its short fields under `@remarks`.
|
|
69
83
|
- Private methods and overload-specific notes use single-line `//` comments, not public TSDoc.
|
|
70
84
|
- Do not document speculative future product behavior unless requested.
|
|
@@ -60,13 +60,22 @@ Define aliases in `tsconfig.json` first. `vite.config.ts` derives from `compiler
|
|
|
60
60
|
- `*/types.ts`: public API contracts.
|
|
61
61
|
- `configs/src/` and `configs/app/`: thin per-target wrappers, including optional
|
|
62
62
|
`configs/src/*bin*` files. Shared logic remains in root configs.
|
|
63
|
-
- `configs/helpers.ts` and `configs/
|
|
64
|
-
imports nothing from the workspace, which is what keeps it a leaf. Each
|
|
65
|
-
imports the root config rather than a leaf, so shared build logic stays
|
|
63
|
+
- `configs/helpers.ts`, `configs/browsers.ts`, and `configs/policy.ts`: the only permitted leaves
|
|
64
|
+
under `configs/`. Each imports nothing from the workspace, which is what keeps it a leaf. Each
|
|
65
|
+
`configs/src/*.config.ts` imports the root config rather than a leaf, so shared build logic stays
|
|
66
|
+
in one place.
|
|
66
67
|
- Keep `configs/helpers.ts` free of any dependency a core-only workspace does not declare. It is
|
|
67
68
|
vendored byte-identical to every workspace, so an import there must resolve in all of them.
|
|
68
69
|
`configs/browsers.ts` exists for that reason: it imports `playwright` and
|
|
69
70
|
`@vitest/browser-playwright`, and only a workspace with a browser environment is given it.
|
|
71
|
+
- Keep `configs/policy.ts` free of imports entirely. It is the workspace's oxlint plugin, the lint
|
|
72
|
+
instrument of the policy law, and it is vendored byte-identical to every workspace including a
|
|
73
|
+
core-only one, so a module that imports nothing at all is the only form that resolves in all of
|
|
74
|
+
them. Because it may import nothing, keep its own types, data, and functions in that one file: the
|
|
75
|
+
centralized-kind placement in `.claude/rules/architecture.md` does not reach it.
|
|
76
|
+
- When a file is vendored byte-identical, import nothing that fails to resolve in any target. Import
|
|
77
|
+
no `@orkestrel/*` package from it: every such package is itself a target and cannot depend on
|
|
78
|
+
itself.
|
|
70
79
|
|
|
71
80
|
Environment rules:
|
|
72
81
|
|
|
@@ -114,15 +123,20 @@ environment:
|
|
|
114
123
|
The second axis is cross-cutting workspace proofs. Each one covers the whole workspace rather than
|
|
115
124
|
one environment, so each is its own project:
|
|
116
125
|
|
|
117
|
-
| Project | Files | Proves
|
|
118
|
-
| -------------- | ---------------------------- |
|
|
119
|
-
| `policy` | `tests/policy.test.ts` | Every source file obeys the syntactic coding and placement law
|
|
120
|
-
| `config` | `tests/config.test.ts` | Root configuration resolves its aliases, projects, and outputs
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
+
| Project | Files | Proves | Gate |
|
|
127
|
+
| -------------- | ---------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
128
|
+
| `policy` | `tests/policy.test.ts` | Every source file obeys the syntactic coding and placement law | `test` |
|
|
129
|
+
| `config` | `tests/config.test.ts` | Root configuration resolves its aliases, projects, and outputs | `test` |
|
|
130
|
+
| `setup` | `tests/setup*.test.ts` | Reusable behavior exported from the root test setup modules works as the consuming suites require | `test` |
|
|
131
|
+
| `guides` | `tests/guides.test.ts` | Every documented API exists and every public API is documented | `test` |
|
|
132
|
+
| `conformance` | `tests/conformance.test.ts` | Where this package drifts from the official tooling it tracks | `test` |
|
|
133
|
+
| `distribution` | `tests/distribution.test.ts` | The packed package installs and resolves through its public exports | `prepublishOnly`; absent when private |
|
|
134
|
+
| `integration` | `tests/integration.test.ts` | The package's features work together end to end across environments | `test` |
|
|
135
|
+
| `service` | `tests/service/**/*.test.ts` | The live external services this package drives, driven for real | `prepublishOnly`; `test` when private |
|
|
136
|
+
|
|
137
|
+
- Define the `setup` project only when a root file matches `tests/setup*.test.ts`, exact-case.
|
|
138
|
+
Include every matching file. When registered, emit `test:setup` and run it from `test`. When no
|
|
139
|
+
file matches, emit neither the project nor the script.
|
|
126
140
|
|
|
127
141
|
`conformance`, `integration`, `distribution`, and `service` are four subjects, not four names for
|
|
128
142
|
one.
|
|
@@ -155,7 +169,7 @@ Setup assets:
|
|
|
155
169
|
- Styles setup loads `setup.css` and the compiled cascade.
|
|
156
170
|
|
|
157
171
|
Scope with `test:src`, `test:src:core`, `test:app`, `test:app:server`, and equivalent scripts. Each
|
|
158
|
-
cross-cutting project has its own script too: `test:policy`, `test:config`, `test:guides`,
|
|
172
|
+
cross-cutting project has its own script too: `test:policy`, `test:config`, `test:setup`, `test:guides`,
|
|
159
173
|
`test:conformance`, `test:distribution`, `test:integration`, `test:service`.
|
|
160
174
|
|
|
161
175
|
## Typechecking and environment isolation
|
|
@@ -225,6 +239,22 @@ Run `show` only **after** formatting. The committed `demo/showcase.html` is gene
|
|
|
225
239
|
- Node build targets derive from the package's declared supported runtime. Keep `engines`, bundler targets, scoped configs, tests, and documentation aligned; never hard-code one Node version line-wide.
|
|
226
240
|
- Browser framework: Vue 3 when present.
|
|
227
241
|
|
|
242
|
+
Policy instruments:
|
|
243
|
+
|
|
244
|
+
- Put every rule of the policy law in exactly one of two instruments. `configs/policy.ts` — the
|
|
245
|
+
oxlint plugin, namespace `policy` — takes the rules a single file's AST decides. The policy sweep
|
|
246
|
+
(`tests/setupPolicy.ts`) takes the rules that are path- or text-shaped, and every rule whose
|
|
247
|
+
subject is suppression itself.
|
|
248
|
+
- Choose between them by what can defeat the rule: an instrument must not be suppressible by the
|
|
249
|
+
thing it polices. A file-level `oxlint-disable` silently defeats every lint rule in its file,
|
|
250
|
+
plugin rules included, and nothing inside a file can suppress the sweep.
|
|
251
|
+
- Write each visitor in the plugin's visitor table as a one-line context-binding arrow delegating to
|
|
252
|
+
a named module-scope `report{Noun}` function. Never write rule logic inline in the table. That
|
|
253
|
+
arrow is the sanctioned exception to the in-body function-expression limits in
|
|
254
|
+
`.claude/rules/architecture.md` for exactly that table.
|
|
255
|
+
- Name no individual rule id here. This section fixes the two instruments and how work is assigned
|
|
256
|
+
between them; each rule's substance stays with the law it enforces.
|
|
257
|
+
|
|
228
258
|
## Text integrity
|
|
229
259
|
|
|
230
260
|
- Store text as UTF-8.
|