@orkestrel/scaffold 0.0.2 → 0.0.3

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 (78) hide show
  1. package/README.md +29 -15
  2. package/dist/bin/scaffold.js +1162 -1200
  3. package/dist/bin/scaffold.js.map +1 -1
  4. package/dist/host/AGENTS.md +124 -925
  5. package/dist/host/CLAUDE.md +260 -495
  6. package/dist/host/agents/skills/orkestrel-align-packages/SKILL.md +53 -0
  7. package/dist/host/agents/skills/orkestrel-align-packages/agents/openai.yaml +4 -0
  8. package/dist/host/agents/skills/orkestrel-align-packages/references/fleet.md +50 -0
  9. package/dist/host/agents/skills/orkestrel-align-packages/references/integration.md +56 -0
  10. package/dist/host/agents/skills/orkestrel-build-application/SKILL.md +64 -0
  11. package/dist/host/agents/skills/orkestrel-build-application/agents/openai.yaml +4 -0
  12. package/dist/host/agents/skills/orkestrel-build-application/references/application.md +129 -0
  13. package/dist/host/agents/skills/orkestrel-harden-package/SKILL.md +64 -0
  14. package/dist/host/agents/skills/orkestrel-harden-package/agents/openai.yaml +4 -0
  15. package/dist/host/agents/skills/orkestrel-harden-package/references/centralization.md +85 -0
  16. package/dist/host/agents/skills/orkestrel-harden-package/references/contract.md +57 -0
  17. package/dist/host/agents/skills/orkestrel-harden-package/references/hardening.md +93 -0
  18. package/dist/host/agents/skills/orkestrel-harden-package/references/research.md +61 -0
  19. package/dist/host/claude/agents/application.md +32 -0
  20. package/dist/host/claude/agents/builder.md +12 -7
  21. package/dist/host/claude/agents/checker.md +15 -8
  22. package/dist/host/claude/agents/codex.md +40 -0
  23. package/dist/host/claude/agents/grok.md +20 -37
  24. package/dist/host/claude/agents/orkestrel.md +89 -223
  25. package/dist/host/claude/agents/planner.md +14 -34
  26. package/dist/host/claude/agents/reviewer.md +39 -24
  27. package/dist/host/claude/agents/verifier.md +15 -10
  28. package/dist/host/claude/rules/application.md +57 -0
  29. package/dist/host/claude/rules/architecture.md +179 -0
  30. package/dist/host/claude/rules/browser.md +28 -0
  31. package/dist/host/claude/rules/documentation.md +64 -0
  32. package/dist/host/claude/rules/names.md +209 -0
  33. package/dist/host/claude/rules/patterns.md +130 -0
  34. package/dist/host/claude/rules/quality.md +45 -0
  35. package/dist/host/claude/rules/styles.md +64 -0
  36. package/dist/host/claude/rules/tests.md +123 -0
  37. package/dist/host/claude/rules/typescript.md +78 -0
  38. package/dist/host/claude/rules/workspace.md +180 -0
  39. package/dist/host/claude/settings.json +116 -0
  40. package/dist/host/claude/skills/orkestrel-align-packages/SKILL.md +10 -0
  41. package/dist/host/claude/skills/orkestrel-build-application/SKILL.md +12 -0
  42. package/dist/host/claude/skills/orkestrel-harden-package/SKILL.md +10 -0
  43. package/dist/host/codex/agents/analyst.toml +15 -0
  44. package/dist/host/codex/agents/application.toml +25 -0
  45. package/dist/host/codex/agents/builder.toml +24 -0
  46. package/dist/host/codex/agents/checker.toml +15 -0
  47. package/dist/host/codex/agents/grok.toml +17 -0
  48. package/dist/host/codex/agents/implementer.toml +17 -0
  49. package/dist/host/codex/agents/orkestrel.toml +16 -0
  50. package/dist/host/codex/agents/planner.toml +20 -0
  51. package/dist/host/codex/agents/reviewer.toml +18 -0
  52. package/dist/host/codex/agents/verifier.toml +14 -0
  53. package/dist/host/codex/config.toml +64 -0
  54. package/dist/host/dotfiles/oxlintrc.json +307 -1
  55. package/dist/host/guides/src/scaffold.md +2059 -2007
  56. package/dist/host/manifest.json +355 -137
  57. package/dist/host/scripts/codex.sh +49 -0
  58. package/dist/host/scripts/cursor.sh +33 -47
  59. package/dist/host/scripts/deps.sh +34 -16
  60. package/dist/host/scripts/ollama.sh +6 -149
  61. package/dist/host/tests/setupPolicy.ts +354 -0
  62. package/dist/src/core/index.cjs +6600 -1199
  63. package/dist/src/core/index.cjs.map +1 -1
  64. package/dist/src/core/index.d.cts +801 -266
  65. package/dist/src/core/index.d.ts +801 -266
  66. package/dist/src/core/index.js +6518 -1191
  67. package/dist/src/core/index.js.map +1 -1
  68. package/dist/src/server/index.cjs +3132 -593
  69. package/dist/src/server/index.cjs.map +1 -1
  70. package/dist/src/server/index.d.cts +643 -95
  71. package/dist/src/server/index.d.ts +643 -95
  72. package/dist/src/server/index.js +3054 -594
  73. package/dist/src/server/index.js.map +1 -1
  74. package/package.json +15 -12
  75. package/dist/host/claude/agents/composer.md +0 -64
  76. package/dist/host/claude/agents/researcher.md +0 -38
  77. package/dist/host/claude/agents/scout.md +0 -35
  78. package/dist/host/github/workflows/ci.yml +0 -64
@@ -0,0 +1,209 @@
1
+ ---
2
+ paths:
3
+ - '**/*.{ts,tsx,mts,cts,vue}'
4
+ ---
5
+
6
+ # Naming and API-shape rules
7
+
8
+ Names are public API. A consumer should be able to predict them without documentation.
9
+
10
+ ## Entity-scoped names: one word
11
+
12
+ Properties/getters, methods, option keys, and event names belong to an entity whose type already supplies context. Use one descriptive word:
13
+
14
+ ```ts
15
+ interface AgentInterface {
16
+ readonly id: string
17
+ readonly context: AgentContextInterface
18
+ readonly status: AgentStatus
19
+ generate(): Promise<string>
20
+ stream(options?: AgentStreamOptions): AsyncGenerator<string, string>
21
+ abort(): void
22
+ }
23
+ ```
24
+
25
+ Hard targets:
26
+
27
+ - Public properties: one word.
28
+ - Public methods: one word; use two only when no single verb is accurate.
29
+ - Ungrouped option keys: one word.
30
+ - Grouped option key: the configured entity noun; every leaf remains one word.
31
+ - Events: one present-tense verb or noun.
32
+ - Private methods: two or three words are acceptable.
33
+
34
+ The rule does not apply to standalone helpers, type names with role suffixes, or qualified constants.
35
+
36
+ ## Split instead of compounding
37
+
38
+ A compound entity member usually means the API contains multiple entities or behaviors. Do not create `addTool`, `removeDocument`, `databasePath`, or `serverTimeout`.
39
+
40
+ ### Group options by entity
41
+
42
+ ```ts
43
+ interface ServerOptions {
44
+ readonly server?: { readonly port?: number; readonly timeout?: number }
45
+ readonly database?: { readonly path?: string; readonly timeout?: number }
46
+ }
47
+ ```
48
+
49
+ Never flatten these into prefixed keys.
50
+
51
+ ### Extract sub-entities
52
+
53
+ Move prefixed method families to a manager and expose it as a noun:
54
+
55
+ ```ts
56
+ interface AgentContextInterface {
57
+ readonly instructions: InstructionManagerInterface
58
+ readonly documents: DocumentManagerInterface
59
+ readonly tools: ToolManagerInterface
60
+ }
61
+ ```
62
+
63
+ Call `context.instructions.add(input)`, not `context.addInstruction(input)`.
64
+
65
+ ### Split behavioral variants
66
+
67
+ Do not hide multiple algorithms behind a discriminator parameter:
68
+
69
+ ```ts
70
+ parseJSON(input)
71
+ parseYAML(input)
72
+ parseTOML(input)
73
+ ```
74
+
75
+ Do not write `parse(input, format)`. A literal that selects a different action is a magic mode and requires separate functions/methods.
76
+
77
+ Distinguish behavior from data:
78
+
79
+ - Different value selects a different action/algorithm/shape of work → split.
80
+ - Different value selects a datum for the same operation → keep it as data.
81
+ - Discriminants, reasoning/error codes, uniformly applied value enums, and field/key selectors are data.
82
+
83
+ ## Standalone helpers
84
+
85
+ Module helpers have no owning entity at the call site, so default to `{verb}{Noun}`:
86
+
87
+ `generateId`, `computeHash`, `extractColumns`, `derivePhaseStatus`, `inferLanguage`, `normalizePath`, `sanitizeFilename`, `matchesGlobPattern`, `belongsTo`, `hasMany`.
88
+
89
+ - A one-word helper is valid only when its meaning and arguments are unmistakable: `delay`, `clamp`, `tokenize`, `similarity`.
90
+ - Reject vague helpers such as `process` or `handle`.
91
+ - A helper prefix has one project-wide meaning: `extract*` extracts structure, `infer*` derives, `compute*` calculates deterministically, and `matches*` is a predicate.
92
+ - When a helper family grows around one shape, promote it to a class with entity-scoped one-word methods.
93
+
94
+ ## General vocabulary
95
+
96
+ - Describe what a thing is, not its implementation.
97
+ - Prefer short common English; avoid jargon, abbreviations, and non-universal acronyms.
98
+ - One concept has one word project-wide. Do not alternate `count`/`length`/`size`/`total` or `abort`/`cancel`.
99
+ - Properties are nouns; methods are verbs.
100
+ - Booleans read as assertions: `aborted`, `exhausted`, `expired`.
101
+ - A binary behavior switch is a boolean, such as `bail`; never model it as `'continue' | 'halt'`.
102
+ - Genuine discriminants, multi-state lifecycles, conventional value pairs (`ascending`/`descending`, `and`/`or`), and external-spec literals remain unions.
103
+ - Absence is `undefined`, never `'none'`, `'unset'`, `'unknown'`, `''`, `-1`, or another sentinel. Use `null` only when an external protocol distinguishes it from omission.
104
+ - Derive facts from existing state through a getter or at the use site. Do not store a duplicate boolean/string label that can drift.
105
+ - Use a union only for irreducible modes, phases, discriminants, or external values.
106
+ - Accessors use bare nouns, never `get*`/`set*`.
107
+ - A discriminant names its axis (`relationship`, `command`, `category`, `operation`, `via`), never `kind` or `type`.
108
+
109
+ ## Acronyms
110
+
111
+ Keep canonical case:
112
+
113
+ - Initialisms: `JSON`, `HTTP`, `NDJSON`, `SSE`, `URL`, `URI`, `SQL`, `API`, `DB`, `TTL`, `UUID`, `RFC`, `JWT`.
114
+ - Brands/proper names: `SQLite`, `IndexedDB`, `GitHub`, `OAuth`.
115
+ - PascalCase identifiers preserve the acronym: `JSONSchema`, `HTTPServer`, `NDJSONParser`, `SSEStream`, `URLPattern`, `SQLiteDriver`, `IndexedDBDriver`.
116
+ - camelCase lowers an acronym only when it leads: `jsonValue`, `urlPath`, `sqlText`; otherwise preserve it: `parseJSON`, `toJSON`, `fromNDJSON`, `signJWT`, `compileSQL`.
117
+ - Ecosystem-conventional `id` and leading `url`/`uri` remain lowercase.
118
+ - Domain folders remain lowercase: `http/`, `sqlite/`, `indexeddb/`, `websocket/`.
119
+ - Never title-fold canonical acronyms into `Json`, `Ndjson`, `Http`, `Sse`, or `Sqlite`.
120
+
121
+ ## Type-level identifiers
122
+
123
+ | Kind | Required form |
124
+ | ------------------------- | --------------------------------------- |
125
+ | Behavioral interface | `{Entity}Interface` |
126
+ | Options/config | `{Entity}Options` |
127
+ | Creation input | `{Entity}Input` |
128
+ | Outcome/output | `{Entity}Result` |
129
+ | Execution context | `{Entity}Context` |
130
+ | Event map | `{Entity}EventMap` |
131
+ | Union/enum-like | `{Entity}{Noun}` |
132
+ | Plain non-behavioral data | `{Entity}` |
133
+ | Function type | `{Entity}Handler` or `{Entity}Function` |
134
+ | Manager interface | `{Entity}ManagerInterface` |
135
+
136
+ - Never prefix interfaces with `I`.
137
+ - Never pluralize type names.
138
+ - `Handler` is for function types, never classes.
139
+
140
+ ## Value-level identifiers
141
+
142
+ | Kind | Required form |
143
+ | -------------- | ------------------------------------- |
144
+ | Class | PascalCase `{Entity}` |
145
+ | Manager class | PascalCase `{Entity}Manager` |
146
+ | Factory | camelCase `create{Entity}` |
147
+ | Guard | camelCase `is{Condition}` |
148
+ | Helper | camelCase `{verb}{Noun}` |
149
+ | Constant | UPPER_SNAKE_CASE `{QUALIFIER}_{NOUN}` |
150
+ | Property/field | camelCase bare noun |
151
+ | Method | camelCase bare verb |
152
+ | Boolean | camelCase adjective/past participle |
153
+
154
+ ## Fixed derivation/construction forms
155
+
156
+ - `is*`: total `Guard<T>`; never throws; returns false off-shape.
157
+ - `parse*`: coercion producing `T | undefined`; cross-type conversion never belongs in a guard.
158
+ - `create*`: factory constructing an entity/value.
159
+ - `*Of`: builder combining constituent parts into a container/guard/value, such as `arrayOf(guard)` or `boundsOf(min, max)`.
160
+ - `{noun}To{Noun}`: projection from a whole to a derived view, such as `definitionToSnapshot`.
161
+ - `*Shape`: `ContractShape` value/JSON-Schema blueprint, not a function or type.
162
+ - Leading `_`: intentionally unused binding only; never privacy.
163
+
164
+ For `_` bindings:
165
+
166
+ - Use only for genuine callback/signature conformance, rest omission, swallowed catches, or intentionally unused loop variables.
167
+ - Verify each use is intentional; remove `_` and wire the value if it should be consumed.
168
+ - Remove the parameter when signature compatibility does not require it.
169
+ - Prefer a short justification for each rare `_` in `src/`.
170
+
171
+ ## Tallies
172
+
173
+ - A lone unambiguous tally is `count`.
174
+ - When several distinct tallies coexist, name each fact: a pool may expose `size`, `idle`, and `active`; a queue may expose `count` and `active`.
175
+ - Do not expose several ambiguous `count` properties.
176
+
177
+ ## Files and folders
178
+
179
+ | Kind | Pattern |
180
+ | -------------- | -------------------------------------------- |
181
+ | Domain folder | lowercase plural entity: `agents/`, `tools/` |
182
+ | Implementation | PascalCase entity: `Agent.ts` |
183
+ | Test | PascalCase entity + `.test`: `Agent.test.ts` |
184
+ | Guide | lowercase domain: `agents.md` |
185
+
186
+ ## Fixed lifecycle vocabulary
187
+
188
+ | Verb | Exact meaning |
189
+ | --------- | ----------------------------------------- |
190
+ | `start` | Begin or restart |
191
+ | `stop` | End permanently |
192
+ | `pause` | Suspend resumably |
193
+ | `resume` | Continue after pause |
194
+ | `skip` | Mark intentionally unexecuted |
195
+ | `abort` | Cancel with signal propagation |
196
+ | `clear` | Reset state without destroying the entity |
197
+ | `destroy` | Tear down and release resources |
198
+ | `execute` | Run primary work to completion |
199
+
200
+ Never introduce synonyms such as `cancel`, `reset`, or `run` for these meanings.
201
+
202
+ ## Rejected naming
203
+
204
+ - Generic words: `data`, `info`, `item`, `thing`, `obj`.
205
+ - Type-encoded names: `nameString`, `countNumber`.
206
+ - Abbreviations: `cfg`, `doc`, `msg`; write `config`, `document`, `message`.
207
+ - `@internal` methods; use `#` privacy.
208
+ - Compound entity members where grouping/extraction/splitting provides the context.
209
+ - Behavior-selecting magic strings.
@@ -0,0 +1,130 @@
1
+ ---
2
+ paths:
3
+ - 'src/**/*.ts'
4
+ - 'app/**/*.{ts,vue}'
5
+ - 'tests/**/*.ts'
6
+ ---
7
+
8
+ # API pattern rules
9
+
10
+ ## Declared ecosystem capabilities
11
+
12
+ Before writing a guard, parser, combinator, outcome, safe exception boundary, contract shape/compiler, schema utility, error narrower, emitter helper, or other general primitive:
13
+
14
+ 1. Inspect `package.json`, the lockfile, vendored dependency guides, and exact installed declarations/exports.
15
+ 2. Build a semantic overlap map between the proposed/local behavior and declared `@orkestrel/*` capabilities.
16
+ 3. Reuse the originating package directly when semantics match.
17
+ 4. Keep local behavior only when it adds a real domain invariant, composition, projection, translation, or intentionally different contract.
18
+ 5. Test the difference. Similar names are not proof of equivalent semantics.
19
+
20
+ Never reimplement or rename-wrap a declared package primitive. Do not add an ecosystem dependency unless the user explicitly authorizes it.
21
+
22
+ ## Options
23
+
24
+ - Top-level keys are single words.
25
+ - Group related settings beneath the configured entity noun; every leaf is one word.
26
+ - Never encode grouping through prefixes such as `serverPort` or `databasePath`.
27
+ - Reserve `on` exclusively for initial `EmitterHooks`.
28
+ - Explain short option keys in TSDoc `@remarks`, not through longer names.
29
+
30
+ ```ts
31
+ interface ServerOptions {
32
+ readonly on?: EmitterHooks<ServerEventMap>
33
+ readonly error?: EmitterErrorHandler
34
+ readonly server?: { readonly port?: number; readonly timeout?: number }
35
+ readonly database?: { readonly path?: string }
36
+ }
37
+ ```
38
+
39
+ ## Managers
40
+
41
+ ### Accessors
42
+
43
+ Managers expose one item and all items through singular/plural domain nouns:
44
+
45
+ ```ts
46
+ entity(key): EntityInterface | undefined
47
+ entities(): readonly EntityInterface[]
48
+ ```
49
+
50
+ Examples: `timeout(id)`/`timeouts()`, `agent(id)`/`agents()`.
51
+
52
+ ### Batch operations
53
+
54
+ One single-word verb carries three overloads:
55
+
56
+ ```ts
57
+ method(): void
58
+ method(id: string): boolean
59
+ method(ids: readonly string[]): boolean
60
+ ```
61
+
62
+ - No argument applies to all.
63
+ - One id applies to one.
64
+ - An id list applies to those items and returns true only when all succeed.
65
+ - Never split into `methodAll`, `methodOne`, or `methodMany`.
66
+ - When a single item type can itself be a list/open record, declare the array overload first and document how callers express one list-valued item.
67
+
68
+ ## Stateful emitters
69
+
70
+ An entity with lifecycle transitions, constraints, or observable operations owns an emitter by composition:
71
+
72
+ 1. Define `{Entity}EventMap` in `types.ts`.
73
+ 2. Add `readonly on?: EmitterHooks<{Entity}EventMap>` and `readonly error?: EmitterErrorHandler` to options.
74
+ 3. Add `readonly emitter: EmitterInterface<{Entity}EventMap>` to the interface.
75
+ 4. Store `readonly #emitter: Emitter<{Entity}EventMap>` and expose it through `get emitter()`.
76
+ 5. Initialize with both hooks and error handling: `new Emitter({ on: options?.on, error: options?.error })`. Positional constructors thread both values equivalently.
77
+ 6. Emit directly with `this.#emitter.emit(...)`; do not add a guarded `#notify`.
78
+ 7. Call `this.#emitter.destroy()` last in the entity's `destroy()`.
79
+
80
+ Never inherit from `Emitter`, write delegation boilerplate, or use `Omit` to reshape it.
81
+
82
+ ### Listener isolation
83
+
84
+ - The emitter isolates each listener; one throw never prevents sibling listeners.
85
+ - It reports every listener throw to its own `(error, event)` error handler.
86
+ - It never rethrows a listener error.
87
+ - A throwing error handler is swallowed to prevent recursion.
88
+ - Never add `observerError` or another listener-failure event to a domain `EventMap`.
89
+ - A genuine domain I/O/transport `error` event is distinct and remains valid.
90
+
91
+ ### Browser/DOM variant
92
+
93
+ In a pure browser-DOM environment where each entity already owns a host `Element`, the element may be the event host:
94
+
95
+ - emit a typed bubbling `CustomEvent` through shared dispatch helpers;
96
+ - subscribe with shared listener helpers;
97
+ - bind `options.on` through one `bindEventMap` helper.
98
+
99
+ Choose one event model per environment. `Emitter<TMap>` remains the default outside exclusively DOM-bound environments.
100
+
101
+ ### Event maps
102
+
103
+ - Event names are single present-tense verbs or nouns: `start`, `connect`, `expire`, `exhaust`, `drain`, `chunk`.
104
+ - Never publish a generic `status` event carrying a transition value; publish each transition as its own event.
105
+ - Type errors as `unknown`.
106
+ - Use empty tuples for signals and labeled tuple elements for IDE clarity.
107
+ - Keep an entity's event map focused, normally four to eight events.
108
+
109
+ ## Validation and contracts
110
+
111
+ Use four orthogonal contract mechanisms:
112
+
113
+ | Surface | Contract |
114
+ | ---------------- | ----------------------------------------------------------------------------- |
115
+ | `validators.ts` | Total `is*` guards: `(unknown) => value is T`; no coercion/side effects |
116
+ | `combinators.ts` | Build guards from guards: `arrayOf`, `recordOf`, `unionOf` |
117
+ | `parsers.ts` | Flat coercers returning `T \| undefined` |
118
+ | Shape DSL | One `ContractShape` compiled into schema, guard, parser, and seeded generator |
119
+
120
+ - Use plain guards/parsers for small contracts.
121
+ - Use the shape DSL only when four-way validation/serialization/generation parity earns its complexity.
122
+ - When `@orkestrel/contract` is declared, use its exact installed guards, parsers, combinators, outcomes, `attempt` boundary, and shape DSL wherever their semantics match. Do not maintain a local copy of those primitives.
123
+ - A guard never throws for adversarial input, cycles, deep nesting, or hostile prototypes; return false.
124
+ - Recursive guards track ancestors and cap depth.
125
+ - Recursion enters only through an explicit lazy gate.
126
+ - Non-lazy structural cycles fail at build time, not runtime.
127
+ - Parse/guard soundness is mandatory:
128
+ - guard-valid input is never rejected by its parser;
129
+ - every parsed result satisfies its guard.
130
+ - Derive parser and guard from one source or test the round trip.
@@ -0,0 +1,45 @@
1
+ ---
2
+ paths:
3
+ - 'src/**/*'
4
+ - 'app/**/*'
5
+ - 'tests/**/*'
6
+ - 'guides/**/*'
7
+ - 'package.json'
8
+ - 'vite.config.ts'
9
+ - 'tsconfig.json'
10
+ - '.agents/skills/**/*'
11
+ - '.claude/skills/**/*'
12
+ ---
13
+
14
+ # Research, hardening, and completion rules
15
+
16
+ ## Evidence before change
17
+
18
+ - Research is mandatory when the user requests it, when comparing an upstream/protocol/legacy implementation, or when current external behavior materially affects design.
19
+ - Use current primary sources for external capabilities and exact installed declarations/guides for dependencies. Separate verified fact from inference.
20
+ - Read authoritative types and named decision-bearing implementation files first-hand. Delegate bulk supporting context, not the owning design decision.
21
+ - Treat existing code, tests, `old/`, branches, and copied projects as evidence rather than authority.
22
+ - Build a capability/defect matrix before a broad API or production-readiness change. Every row ends as implement, repair, retain, or intentionally exclude with evidence.
23
+
24
+ ## Ecosystem reuse
25
+
26
+ - Inspect declared `@orkestrel/*` packages before implementing overlapping infrastructure.
27
+ - Prefer an exact originating primitive when semantics match; test semantic differences when they do not.
28
+ - Downstream friction is valid evidence of a reusable upstream defect, not automatic proof. Fix the lowest package that owns the general mechanism and keep product policy downstream.
29
+ - Update affected consumers atomically. Never add compatibility shims or dependency re-exports.
30
+
31
+ ## Production hardening
32
+
33
+ - Translate “enterprise-grade” or “production-ready” into an explicit risk/seam matrix covering applicable inputs, states, failures, cleanup, cancellation, concurrency, resource ownership, hostile boundaries, environment isolation, serialization/restore, and package consumption.
34
+ - Test observable invariants at each applicable seam with real implementations.
35
+ - Use dedicated real-service projects for external model/service behavior. Require readiness and tune each request to the smallest robust proof.
36
+ - Audit test discovery, counts, skipped/todo tests, cleanup, and assertion adequacy; passing discovered tests alone is insufficient.
37
+ - Inspect public exports, declarations, supported runtime targets, and generated outputs.
38
+ - Add an independent adversarial review for security, destructive paths, concurrency, protocols, or untrusted external input.
39
+
40
+ ## Completion
41
+
42
+ - Run the applicable repository skill for comprehensive hardening, structural cleanup, contract adoption, or multi-package alignment.
43
+ - Finish every in-scope capability and required finding now. Do not leave TODOs, deferred rows, empty branches, skipped proof, or hidden follow-up work.
44
+ - Perform a final centralization/wrapper/test-helper/text-integrity sweep after implementation and before gates.
45
+ - Local quality gates and relevant output inspection are required evidence.
@@ -0,0 +1,64 @@
1
+ ---
2
+ paths:
3
+ - '**/*.{scss,css}'
4
+ - 'src/styles/**/*'
5
+ - 'tests/setupStyles.ts'
6
+ - 'tests/setupBrowser.ts'
7
+ ---
8
+
9
+ # SCSS and CSS rules
10
+
11
+ SCSS mirrors TypeScript centralization. Concrete token prefixes are project-specific; these structural rules are universal.
12
+
13
+ ## Centralized files
14
+
15
+ | File | Sole responsibility |
16
+ | -------------- | ------------------------------------------------------------- |
17
+ | `_mixins.scss` | `@function` values and `@mixin` declaration emitters |
18
+ | `_tokens.scss` | `:root` public custom-property tokens and cascade-layer order |
19
+ | `_theme.scss` | Token overrides under theme selectors |
20
+ | `index.scss` | Sole compilation barrel |
21
+
22
+ - `_mixins.scss` emits no top-level CSS.
23
+ - Consumers load it with `@use '../mixins' as *`.
24
+ - Never load `mixins` from `index.scss`.
25
+ - `index.scss` is the sole compilation barrel; it loads `tokens`, `theme`, and output partials with `@use`.
26
+ - `_tokens.scss` is the token source of truth. Adding a token is allowed; rename/removal is breaking.
27
+ - `_theme.scss` only retunes tokens under selectors such as `[data-theme='…']`.
28
+ - Component partials never override global tokens.
29
+
30
+ ## Sass mechanisms
31
+
32
+ - `@function`: pure calculation returning one CSS value.
33
+ - `@mixin`: emits declarations and may take `@content`; owns repeated boilerplate.
34
+ - `%placeholder`: sharing inside one partial only. It is not reachable across `@use`; cross-file reuse uses mixins.
35
+
36
+ ## Prohibitions
37
+
38
+ - Check `_tokens.scss` before inventing a token.
39
+ - Put global tokens in `_tokens.scss`; put truly component-scoped custom properties on the component selector.
40
+ - Never bury tokens in unrelated partials.
41
+ - Never use literal colors. Use `var(--token)` or `color-mix()` over tokens.
42
+ - Never repeat per-color/per-variant blocks; drive shared structure with one `@each` over a shared list.
43
+ - If a pattern appears in at least two partials, move it to `_mixins.scss`.
44
+ - A one-partial pattern stays inline; do not create a mixin for one caller.
45
+ - Never `@extend` across partials; share through tokens/mixins.
46
+ - Never declare a `transition:` without `prefers-reduced-motion: reduce`. Use the project transition mixin, which emits both.
47
+ - Animations include `@include reduced-motion { animation: none }`.
48
+ - Never wrap rules in a foreign cascade layer. Each partial uses its folder's own layer.
49
+ - Declare cascade-layer order once in the consumer entry before `@import 'tailwindcss'`, so utilities win predictably.
50
+
51
+ ## Naming
52
+
53
+ | Kind | Form |
54
+ | --------------- | ------------------------------------------------------------------- |
55
+ | Function | lowercase kebab-case verb/noun: `tint`, `clamp` |
56
+ | Mixin | lowercase kebab-case verb/verb-noun: `transition`, `reduced-motion` |
57
+ | Sass variable | lowercase kebab-case; `!default` when overridable |
58
+ | Custom property | project token scheme: `--{scope}-{property}[-modifier]` |
59
+ | Modifier class | bare adjective/noun: `.surface`, `.muted`, `.accent` |
60
+ | State class | bare adjective using the shared lifecycle vocabulary |
61
+
62
+ State classes are bare adjectives such as `.active` and `.disabled`, chosen consistently with the shared lifecycle vocabulary.
63
+
64
+ The composable owns interaction state, class application, `aria-*`, and timing. The partial owns visual presentation. Their contracts are stable class names and transition tokens.
@@ -0,0 +1,123 @@
1
+ ---
2
+ paths:
3
+ - 'tests/**/*'
4
+ - 'vite.config.ts'
5
+ - 'configs/**/*.ts'
6
+ - 'package.json'
7
+ ---
8
+
9
+ # Testing rules
10
+
11
+ ## Test contract
12
+
13
+ - Mirror source/application structure:
14
+ `tests/{src,app}/[environment]/[domain]/[Entity].test.ts`.
15
+ - Prefer test filenames matching entrypoints: `index.test.ts` for `index.ts`, `main.test.ts` for `main.ts`.
16
+ - Tests are deterministic: identical inputs produce identical results.
17
+ - Keep default suites fast: timers normally use 10–50 ms and tests make no network calls.
18
+ - Use real implementations and small scenarios. Never use mocks, behavioral fakes, module replacement, or framework spies for project-owned or integrated behavior.
19
+ - Use recorders for calls/events, temporary resources for stateful boundaries, protocol-faithful fixture servers for deterministic network peers, and the real external service when its behavior is the claim.
20
+ - Prefer inert customizable data/input stubs. A scripted boundary stub is allowed only when it implements the real interface/protocol minimally to drive the system under test; it never reimplements project-owned behavior or stands in for the integration being claimed.
21
+ - Cover happy paths, error paths, empty input, boundary values, `NaN`, positive/negative zero, cycles, and Map/Set order where relevant.
22
+ - Test observable behavior, not implementation details.
23
+ - Use `it.todo()` only for explicitly out-of-scope roadmap work, never to complete the current request. Every `.skip` or conditional skip has a narrow verifiable applicability reason.
24
+ - Do not create test files solely for `constants.ts`, barrels, error definitions, or `types.ts`.
25
+ - Run the narrowest relevant Vitest project during development; do not run the entire suite casually.
26
+
27
+ ## Live-service tests
28
+
29
+ Live external services/models are the deliberate exception to fast hermetic defaults:
30
+
31
+ - Put them in a dedicated isolated Vitest project with its own setup and longer timeout.
32
+ - Keep them out of the default run.
33
+ - Warm and verify service readiness in setup.
34
+ - Hard-require readiness: throw loudly; never silently skip.
35
+ - Verify service-dependent logic through that service's project, not unrelated module tests or scattered conditional skips.
36
+ - Tune each request to the smallest input/context/output that proves one behavior without becoming brittle or expensive.
37
+ - Prefer semantic bounded assertions over exact generated prose. Increase context/workload only when the scenario requires it.
38
+
39
+ ## Shared test infrastructure
40
+
41
+ Test helpers are shared infrastructure, not local test-file clutter.
42
+
43
+ - 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.
44
+ - Any duplicate or near-duplicate helper is a defect; consolidate it into one general form.
45
+ - Export every reusable helper, fixture type, factory, constant, and guard from setup files.
46
+ - Test files import shared infrastructure rather than declaring local fixture factories.
47
+ - Never reimplement a framework helper in tests or fixtures; import the real parser, signer, flattener, or other helper.
48
+ - Prefer small customizable factories/stubs that seed inert data for a real scenario over repeated inline setup.
49
+ - Helper names follow module-helper naming: `createRecorder`, `buildElement`, `appendItems`, `renderRows`, `waitForDelay`, `extractDetail`.
50
+
51
+ Place helpers by environment:
52
+
53
+ - `tests/setup.ts`: host-independent; no `node:*`, DOM, `window`, or Vue.
54
+ - `tests/setupServer.ts`: Node-only helpers and `node:fs` loaders anchored to `WORKSPACE_ROOT`.
55
+ - `tests/setupBrowser.ts`: DOM/Vue/browser helpers and setup CSS.
56
+ - `tests/setupStyles.ts`: CSS/style helpers and compiled cascade.
57
+
58
+ ### Recorder
59
+
60
+ Use a real recorder callback instead of a framework spy when only calls/arguments matter:
61
+
62
+ ```ts
63
+ interface TestRecorderInterface<TArgs extends readonly unknown[]> {
64
+ readonly calls: readonly TArgs[]
65
+ readonly count: number
66
+ readonly handler: (...args: TArgs) => void
67
+ clear(): void
68
+ }
69
+ ```
70
+
71
+ ### Delay
72
+
73
+ Use the shared delay helper; never repeat inline timeout promises:
74
+
75
+ ```ts
76
+ export function waitForDelay(ms = 0): Promise<void> {
77
+ return new Promise((resolve) => setTimeout(resolve, ms))
78
+ }
79
+ ```
80
+
81
+ ### Style primitives
82
+
83
+ Browser/style setup exposes shared assertions/builders:
84
+
85
+ `mount`, `render`, `build`, `style`, `token`, `rootToken`, `pixels`, `rgba`, `colorEqual`, `findRule`.
86
+
87
+ `findRule` proves a declaration exists in the cascade; `style()` reads the resolved result.
88
+
89
+ ## Browser tests
90
+
91
+ Use the real browser as the system under test:
92
+
93
+ - Do not replace DOM events, storage, observers, viewports, layout methods, pointer, or drag APIs unless the browser genuinely lacks one.
94
+ - Prefer real nodes, events, styles/layout, and observers.
95
+ - Centralize event factories: `createPointerEvent`, `createDragEvent`, `typeInput`, `fireTransitionEnd`.
96
+ - Centralize DOM builders: `createButtonElement`, `createDropdownElements`, `createModalElement`.
97
+ - Assert DOM state, emitted events, callback records, focus, classes, attributes, and public API state.
98
+ - Do not assert private state, internal timers, or framework scheduler internals.
99
+ - Prefer real short timers and observable wakeups. Never replace the host clock.
100
+
101
+ ## Runner configuration
102
+
103
+ Keep Vitest/provider configuration minimal:
104
+
105
+ - Prefer defaults until a measured problem proves them insufficient.
106
+ - Centralize provider setup in one helper/shared block.
107
+ - Add browser/provider/teardown/timeout/parallelism/cache/launch settings only for a current verified need.
108
+ - Avoid long browser flag lists and persistent contexts unless a test requires them.
109
+ - For slow teardown, inspect test cleanup, open handles, file parallelism, and context churn before adding launch flags.
110
+ - Remove exploratory settings after fixing the cause.
111
+ - Config comments explain the current reason, not the history of failed experiments.
112
+
113
+ ## Discovery and adequacy audit
114
+
115
+ Before acceptance:
116
+
117
+ - prove every intended test file is discovered by the correct project;
118
+ - inspect actual test counts and environments;
119
+ - audit `.todo`, `.skip`, conditional skips, retries, and inflated timeouts;
120
+ - confirm each assertion would fail for the defect it claims to catch;
121
+ - confirm helpers do not reimplement production behavior;
122
+ - confirm cleanup runs after setup or assertion failure;
123
+ - confirm current-scope requirements have real tests rather than placeholders.
@@ -0,0 +1,78 @@
1
+ ---
2
+ paths:
3
+ - '**/*.{ts,tsx,mts,cts,vue}'
4
+ ---
5
+
6
+ # TypeScript rules
7
+
8
+ The non-negotiables in `AGENTS.md` apply without exception.
9
+
10
+ ## Syntax and imports
11
+
12
+ - Tabs for indentation.
13
+ - No semicolons unless ASI requires one.
14
+ - Single quotes.
15
+ - Named exports only, except framework-required defaults.
16
+ - ESM imports use explicit `.js` extensions for local TypeScript modules.
17
+ - Place `import type` declarations before value imports.
18
+ - Do not place blank lines between consecutive imports of the same kind.
19
+ - Use runtime `#` fields, never TypeScript `private`.
20
+ - Accept untrusted values as `unknown`; narrow with total guards.
21
+ - Never assert with `as` or `!`, and never suppress TypeScript/lint diagnostics.
22
+
23
+ ## Types
24
+
25
+ - Put every reusable or public interface/type alias in the nearest authoritative `*/types.ts`.
26
+ - Define the public contract before implementation.
27
+ - Interface properties are readonly.
28
+ - Public collection properties and return types use `readonly T[]`, `ReadonlyMap<K, V>`, or `ReadonlySet<T>`.
29
+ - Parameters are never `readonly`.
30
+ - Optional state is `T | undefined`; optional lookup failure returns `undefined`.
31
+ - Use `null` only when an external protocol/data format gives it semantics distinct from omission.
32
+ - A binary behavior switch is boolean; a literal union must represent real domain modes, phases, discriminants, or external values.
33
+
34
+ ## Immutability
35
+
36
+ - Never mutate caller-owned inputs.
37
+ - Use copy-on-write for internal state.
38
+ - Return copies or readonly views; never leak a mutable internal reference.
39
+ - Compute derived facts instead of persisting duplicate state.
40
+
41
+ ## Errors and outcomes
42
+
43
+ | Condition | Required strategy |
44
+ | ------------------------------------ | ------------------------------------------- |
45
+ | Programmer error or invalid argument | Throw an `AppError` |
46
+ | I/O/network/external operation | Return `Result<T, E>` or throw consistently |
47
+ | Optional missing lookup | Return `undefined` |
48
+ | Invalid input inside a guard | Return `false`; never throw |
49
+
50
+ Use the existing outcome contract from a declared dependency or the owning environment; do not redeclare it at each call site. When no such contract exists and adding a dependency is not authorized, define this once in the owning `types.ts`:
51
+
52
+ ```ts
53
+ interface Success<T> {
54
+ readonly success: true
55
+ readonly value: T
56
+ }
57
+
58
+ interface Failure<E> {
59
+ readonly success: false
60
+ readonly error: E
61
+ }
62
+
63
+ type Result<T, E = Error> = Success<T> | Failure<E>
64
+ ```
65
+
66
+ - When `@orkestrel/contract` is declared, inspect and use its exact installed `Result`, construction/narrowing helpers, and `attempt` behavior instead of duplicating them.
67
+ - Otherwise construct and narrow through the owning environment's centralized helpers.
68
+ - Error classes expose a machine-readable `code` and optional `context`.
69
+ - Every public error class ships with a guard such as `isAppError` for safe `catch` narrowing.
70
+
71
+ ## Comments and API documentation
72
+
73
+ - Comments explain why, never restate what self-explanatory code does.
74
+ - Every public export has complete TSDoc: description, `@param`, `@returns`, and `@example` where applicable.
75
+ - Document an options object as one `@param`; describe its short fields under `@remarks`.
76
+ - Private methods and overload-specific notes use single-line `//` comments, not public TSDoc.
77
+ - Do not document speculative future product behavior unless requested.
78
+ - Never use `@internal` to hide a method; make it `#` private.