@wairon/cli 5.1.1-dev.95 → 5.1.1-dev.97

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.
@@ -70,8 +70,8 @@ You must read, respect, and update the living quest log file: `.wai/phased_desig
70
70
  The full standard is the source of truth; this is the summary you design against.
71
71
 
72
72
  1. **Building blocks** (atomic roles): `Portal` (inbound transport entrypoint), `Orchestrator` (logic as a flowchart over injected collaborators, with one or more cohesive methods; `dependencyClass: pure` depends only on pure Orchestrators, `read` also on read Orchestrators, Repositories, Indexes and Adapters, and unset means a workflow), `Supervisor` (owns the set of live Actors and their lifecycle; may supervise Supervisors), `Actor` (owns one live thing — a session, connection, timer or entity instance — and its methods are full flowcharts), `Store` (authoritative state for one aggregate), `Index` (read-path projection over a Store — reference-sharing, coherent, never stale; as an exceptional case it may project another Index of the same Repository, never in a cycle), `Query` (a Repository member computing reads over its Store per call), `Registry` (write path / CUD for one aggregate), `Adapter` (the only block doing external I/O — DB/FS/HTTP/gRPC/message-bus client), `Observer` (subscribes to events, forwards to one workflow).
73
- - **Strict Layer Isolation**: A `Portal` must **never** depend directly on a `Store`, `Registry`, `Adapter`, or `Query`. Reads MAY go straight through a `Repository` or `Index` facade (passthrough reads need no per-entity Orchestrator ceremony), but a Portal narrative call or dispatch-table binding that reaches a **write**-effect facade method is an error (`PORTAL_WRITE_SHORTCUT`) — every write routes through an inbound `Orchestrator` to keep the presentation/transport layer out of domain mutations.
74
- - **Logic and process rules**: pure logic may be used by every block. A `Supervisor` reaches data only through workflows (its Actors, Orchestrators, Adapters and other Supervisors). A live `Actor` is reached by id through a Supervisor that supervises it, so `dependsOn` lists both; a `Portal` may message a Supervisor by id. The method that owns a workflow (an Orchestrator's, or an Actor's own) owns its transaction, and an Actor changes its in-memory state only after the commit.
73
+ - **Strict Layer Isolation**: A `Portal` must **never** depend directly on a `Store`, `Registry`, `Adapter`, or `Query`. Reads MAY go straight through a `Repository` or `Index` facade (passthrough reads need no per-entity Orchestrator ceremony), but a Portal narrative call or dispatch-table binding that reaches a **write**- or **lifecycle**-effect facade method is an error (`PORTAL_WRITE_SHORTCUT`) — every mutation routes through an inbound `Orchestrator` to keep the presentation/transport layer out of domain mutations.
74
+ - **Logic and process rules**: pure logic may be used by every block. A `Supervisor` may `owns` its **supervision state** — a Store or Registry that is its own (restart counts, live sets, run brackets): one hop, private, full read/write (`SUPERVISOR_CONTAINMENT` for anything else it owns; a component depending on it is the intruder, `SUPERVISION_STATE_INTRUSION`). Shared data it does not own it reaches only through `read`- and `lifecycle`-effect methods; a write goes through an Orchestrator (`SUPERVISOR_WRITE_SHORTCUT`), and it stays out of presentation. A live `Actor` is reached through its supervision: callers look it up by id in a Registry its Supervisor maintains (owns, or keeps through lifecycle calls) — model that real lookup hop — or depend on that Supervisor (`ACTOR_REACHED_WITHOUT_SUPERVISOR`); a `Portal` may message a Supervisor by id. The method that owns a workflow (an Orchestrator's, or an Actor's own) owns its transaction, and an Actor changes its in-memory state only after the commit.
75
75
  - **No wildcard block**: decompose instead. Held or derived state → Store/Index/Repository; behaviour over a value's own fields → a type method; external I/O → Adapter; logic → an Orchestrator with the narrowest `dependencyClass` that holds; one live thing → Actor. `Specialist` and `Gateway` are retired (`STEREOTYPE_RETIRED`): `wairon doctor --fix` retypes a Specialist as an Orchestrator, and a Gateway becomes the Portal it owned, with the `gateway` variant.
76
76
  2. **Patterns** (named compositions; set `owns`): `Repository` — the data-access component for one aggregate: owns one Store + its Registry + Indexes + Queries + optional Adapter; consumers use the facade only, never the inner blocks. A `Query` lives only inside a Repository and depends only on its Store, a backend Adapter or pure logic. Reads across aggregates go through a read Orchestrator (or a read-model Repository whose Query runs the join), and an outbox is a sibling Repository. A pattern owns only building blocks, never another pattern — compose patterns at the subsystem (L1) level.
77
77
  - **Variants** (`variant:` on a component): the built-in `arbiter`, `projector`, `composer` and `codec` (on Orchestrator) and `gateway` (on Portal: authenticates, authorizes, validates or rate-limits before it dispatches, with its inbound auth in `auth`), then any global and project variants, a later layer overriding by id. A variant carries guidance; what an Orchestrator may depend on is its own `dependencyClass`.
@@ -82,7 +82,7 @@ The full standard is the source of truth; this is the summary you design against
82
82
  3. Point every consumer at the `<x>_repository` facade — never at the inner blocks.
83
83
  - *Lightweight exception*: for genuinely simple held state, a deliberately **standalone Store** is sanctioned — consumers from the workflow layer only (a workflow Orchestrator or an Actor), acknowledged with a `lint.allow` reason on the `UNOWNED_STORE` warning. The state stays VISIBLE as a component either way.
84
84
  - *Never*: hold state as fields inside an Orchestrator because a Store link was refused. A refused link means "apply this recipe", not "inline the state" — state hidden inside a logic component is invisible to the spec and unrecoverable.
85
- 3. **owns vs dependsOn**: `owns` = a pattern's private member blocks (exactly one hop). `dependsOn` = collaborators (other facades / standalone blocks). Never depend on a block privately owned by another pattern.
85
+ 3. **owns vs dependsOn**: `owns` = a pattern's private member blocks (exactly one hop), or a Supervisor's supervision state (its own Stores and Registries). `dependsOn` = collaborators (other facades / standalone blocks). Never depend on a block privately owned by another pattern.
86
86
  4. **Decoupling**: Registry (write) and Index (read) are independent — both work on the Store; the Registry never updates Indexes (Indexes share the Store's references and project structural changes). A Store is depended *upon*; it never depends on a Registry/Index. An Index depends on its Store, a backend Adapter or pure logic; only when one projection is itself worth re-presenting another way may a derived Index depend on another Index — owned by the same Repository, never in a cycle (`ARCHITECTURE_VIOLATION_INDEX_DEP` otherwise). Keep it the exception: it is not a way to chain lookups.
87
87
  5. **Behaviour placement**: behaviour lives where it can be performed autonomously over its own state (`order.total()`, `dog.bark()`); behaviour needing an external actor lives on the *acting* component, taking the entity as an argument (a `Carrier` ships an order — not `order.ship()`). Prefer composition + interfaces over inheritance.
88
88
  6. **Narrative coding (L5)**: each method reads top-to-bottom as named steps; one level of abstraction per function; a pattern facade's method is exactly one `call` step (pure 1:1 forwarding, no logic).
@@ -107,7 +107,8 @@ schemas:
107
107
  - **targetLanguage**: set on L0 (`sdd_initialize_system`), override per L1 — enables language-aware validation (foreign builtins and flow constructs the language lacks are flagged). Extension packs (`.wai/project.yaml` → `extensions.packs`) may register additional languages/platforms and custom profiles.
108
108
  - **technologies (L4)**: an external technology (database, vendor SDK, service) is abstracted as a component — wrapped by an Adapter behind an intent-language interface (inside a Repository for persistence; a standalone Adapter for an external API). Declare the binding on that component's L4: `technologies: [mysql]`. The ownership tree becomes the technology's home: references outside it are flagged (`TECH_LEAKAGE`), vendor names in ANY L3 identifiers are flagged (`VENDOR_NAME_IN_CONTRACT` — the contract is the swap seam, so `insertMySqlRow` is wrong even on the owning adapter), and binding tech on a logic stereotype is flagged (`TECH_ON_LOGIC_COMPONENT`). Swapping the technology then touches one L4.
109
109
  - **lint.allow (per-spec suppression)**: any L1–L4/type spec may carry `lint: { allow: [{ code, reason }] }` — silences that WARNING (or NOTICE) code on that spec only (wairon's `#[allow]`). Errors are never locally suppressible; unknown codes and allows that no longer match anything are flagged. Prefer fixing — an allow is for a documented false positive or a deliberate, reviewable exception.
110
- - **Methods (L3)**: prefer structured `params: [{name, type}]` — authoritative for type checking; the prose `signature` is then display-only. `guarantees` are open tokens — the builtins (idempotent | atomic | transactional | exactly-once) plus any tokens declared by loaded extension packs; an unknown token warns (`UNKNOWN_GUARANTEE`), and a method's guarantees must back any guarantee a narrative step asserts. Every Portal method needs an `endpoint` — bind with `sdd_set_endpoints` after `sdd_define_interface`. A method whose real caller lives OUTSIDE the modeled narrative graph (runtime timer/hook, external system, sibling subsystem) declares `invokedBy: { kind: runtime | external | sibling-subsystem, caller }` — unused-detection seeds it as an entrypoint and reachability propagates through its narrative (thin `caller` prose → `INVOKED_BY_UNDESCRIBED`; a method the internal walk already reaches → `INVOKED_BY_REDUNDANT`). Prefer a `register` step when the wiring is internal.
110
+ - **Methods (L3)**: prefer structured `params: [{name, type}]` — authoritative for type checking; the prose `signature` is then display-only.
111
+ - **Types speak one neutral grammar** in every param, returns and field: the primitives `string`, `int`, `float`, `bool`, `bytes`, `date` (a calendar day), `datetime` (an instant), `duration`, `void`, `any`; the collections `list<T>`, `set<T>` and `map<K, V>` (K is `string`, `int` or an enum); `T?` for "T or no value" (an `optional: true` param or field means "may be left out", a different thing); `A | B` only between NAMED types; and `async T` (or `async void`) on a returns that completes later. A named type is an entity, a value-object, an `enum` (`sdd_add_type` kind `enum` with ordered `values`) or a signature type; a value that needs its own meaning but is one primitive is a named scalar, a value-object with `holds: string` (or another primitive) in place of fields. Write `async void`, never `Promise<void>`; `list<Invoice>`, never `Invoice[]`. TypeScript spellings are still accepted and stored canonical — the answer lists each respelling — but `number` is refused ("int or float?"), and inline object shapes, inline function types, literal unions (`'a' | 'b'`) and unions mixing in a primitive are refused with their named replacement (a value-object or named scalar, a signature type, an enum). `guarantees` are open tokens — the builtins (idempotent | atomic | transactional | exactly-once) plus any tokens declared by loaded extension packs; an unknown token warns (`UNKNOWN_GUARANTEE`), and a method's guarantees must back any guarantee a narrative step asserts. Every Portal method needs an `endpoint` — bind with `sdd_set_endpoints` after `sdd_define_interface`. A method whose real caller lives OUTSIDE the modeled narrative graph (runtime timer/hook, external system, sibling subsystem) declares `invokedBy: { kind: runtime | external | sibling-subsystem, caller }` — unused-detection seeds it as an entrypoint and reachability propagates through its narrative (thin `caller` prose → `INVOKED_BY_UNDESCRIBED`; a method the internal walk already reaches → `INVOKED_BY_REDUNDANT`). Prefer a `register` step when the wiring is internal.
111
112
  - **Narratives (L5, inside L4)**: a FLAT numbered step list; order mimics the code lines. `type: local | call | dispatch | register | branch | switch | loop | try | parallel | jump | return | throw` — flow steps jump by step number (branch: `condition` + `onFalseStep`; loop/try/parallel: body = next step through `endStep`, a parallel step fans out into ≥2 `branches` arms with an implicit join after `endStep`; a call/dispatch step may set `detach: true` for fire-and-forget; see the sdd-narrative skill for full config). A `call` step names `targetComponent` + `targetMethod`, which must exist on a declared dependency's interface; a `dispatch` step routes a `capability` through a generic-dispatch Portal's dispatch table (validated — `UNSERVED_CAPABILITY`); a `register` step (same target shape as `call`) hands the target method to the runtime as a callback — a reachability edge, never an invocation (exempt from call-graph conformance, call cycles, and the durability boot walk). Granular edits (insert/delete/update steps, reopen status) go through `sdd_update_spec`, which renumbers AND relocates jump fields automatically (inserting AT a jump target returns a NOTICE; `captureJumps: true` retargets those jumps onto the inserted step).
112
- - **Semantic wiring (dispatch / lifecycle / durability)**: a generic-dispatch Portal declares a machine-readable `dispatch` table (`capability → component.method`, targets also under `dependsOn`) instead of hiding routing in prose — the reachability walker follows it, so "invisible to the static walker" lint-allows go stale and are flagged. Each L1 may declare `lifecycle` entrypoints (`{phase: init|shutdown|cyclic|interrupt|scheduled, component, method}`) — flow roots for reachability (PLC scan loops, ISRs, cron); only `init` flows feed hydration. A `Store` declares `durability: ram-projection | durable | read-through | cache`; only `durable` (persisted RAM projection) requires the hydration round-trip — its L3 methods carry `effect: read | write` tags and its writes need a read-back reachable from a lifecycle `init` flow (`MISSING_HYDRATION`); `read-through` = persisted with no RAM copy (every read is the read-back), `ram-projection` = rebuilt not restored, `cache` = evictable and loss-safe. Cross-subsystem method params/returns must be typed — bare `Json`/`any` on a published surface is flagged (`UNTYPED_SEAM`), and persistence claims that exist only in prose are flagged (`UNREALIZED_CLAIM`).
113
+ - **Semantic wiring (dispatch / lifecycle / durability)**: a generic-dispatch Portal declares a machine-readable `dispatch` table (`capability → component.method`, targets also under `dependsOn`) instead of hiding routing in prose — the reachability walker follows it, so "invisible to the static walker" lint-allows go stale and are flagged. Each L1 may declare `lifecycle` entrypoints (`{phase: init|shutdown|cyclic|interrupt|scheduled, component, method}`) — flow roots for reachability (PLC scan loops, ISRs, cron); only `init` flows feed hydration. A `Store` declares `durability: ram-projection | durable | read-through | cache`; only `durable` (persisted RAM projection) requires the hydration round-trip — its L3 methods carry `effect: read | write | lifecycle` tags and its writes and lifecycle changes need a read-back reachable from a lifecycle `init` flow (`MISSING_HYDRATION`); `lifecycle` creates, destroys or (un)registers what exists without modifying domain fields, and calls only read and lifecycle methods (`LIFECYCLE_CALLS_WRITE`); `read-through` = persisted with no RAM copy (every read is the read-back), `ram-projection` = rebuilt not restored, `cache` = evictable and loss-safe. Cross-subsystem method params/returns must be typed — bare `any` (and what reads as it: `json`, `object`, `unknown`) on a published surface is flagged (`UNTYPED_SEAM`), and persistence claims that exist only in prose are flagged (`UNREALIZED_CLAIM`).
113
114
  - **Narrative detail dial**: per method (or L4 spec-level) `detail: full | calls-only | intent`; omitted = stereotype default (Portal/Observer/Adapter → calls-only, Store/Index/Query/Registry → intent, logic components → full). `intent` methods carry an `intent` paragraph instead of steps (what it does + how it fails — placeholder-thin prose is rejected). Levels are floors, not ceilings.
@@ -23,13 +23,13 @@ You are the **Delegation Orchestrator**. Your job is to hand scoped work to a fo
23
23
  - Pick the agent whose `ownedPaths`/domain matches the task. If no agent fits, stop and tell the user the topology has a gap.
24
24
  2. **Fetch the LIVE brief**:
25
25
  - Call `sdd_get_agent_brief(agentId)` (or read the `wairon-agent://<agentId>` resource).
26
- - The brief carries: `agentId`, `name`, `template`, `domainRoot?`, `ownedPaths`, `readPaths?`, `instructions`, `variantGuidance?`, and — when the project opted into `execution.tier` — `profile` and `budget`.
26
+ - The brief carries: `agentId`, `name`, `template`, `domainRoot?`, `ownedPaths`, `readPaths?`, `instructions`, `variantGuidance?`, `typeMapping?` (how the contracts' neutral types are spelled in the language the agent's code is written in, also folded into `instructions` under `## Types in <language>`), and — when the project opted into `execution.tier` — `profile` and `budget`.
27
27
  - **Never reuse a brief across delegations or after a re-lock** — fetch fresh per delegation; the call is cheap and the brief is always current.
28
28
  3. **Spawn a GENERIC subagent from the brief**:
29
29
  - Prompt: `brief.instructions`, plus the concrete task description.
30
30
  - Write fence: the subagent may only modify files matching `brief.ownedPaths` (within `brief.domainRoot` when set).
31
31
  - Required first reading: `brief.readPaths` — the subagent reads these before any edit.
32
- - Pass `brief.variantGuidance` along when present.
32
+ - Pass `brief.variantGuidance` along when present, and `brief.typeMapping` — the subagent writes `list<T>`, `T?`, `async T` and an enum by that mapping, never by guess.
33
33
  4. **Apply `brief.budget` when it is present** — constituting the subagent correctly is part of spawning it, not a separate concern. When the brief carries no budget the project has not opted in; spawn as you otherwise would.
34
34
  - `modelTier` → your host's model families. On Claude Code: `small`→haiku, `standard`→sonnet, `large`→opus, `frontier`→fable. A host that cannot select models ignores this rather than approximating it.
35
35
  - `effort`, `maxTurns` → pass through where the host supports them. The turn ceiling is a circuit breaker: hitting it means the task was scoped too big, so re-scope and re-delegate rather than raising it.
@@ -29,7 +29,7 @@ You are the **Spec-to-Code Compiler**. Your job is to generate concrete source c
29
29
  stated failure behavior.
30
30
  4. You may not invent new steps.
31
31
  5. You may not omit any steps.
32
- 6. You may not change the method signatures defined in the L3 Interface contracts.
32
+ 6. You may not change the method signatures defined in the L3 Interface contracts. Contracts spell types in wairon's neutral grammar (`list<T>`, `map<K, V>`, `T?`, `async T`, `int`/`float`, an enum); write each in your language by the brief's type mapping (`typeMapping`, the `## Types in <language>` section) — in TypeScript `list<T>` is `T[]`, `T?` is `T | null`, `async T` is `Promise<T>`, and an enum is a string-literal union alias.
33
33
  7. All code must match the declarative nature of the blueprints.
34
34
  8. You must strictly follow the inlined **Core Architecture & Coding Standards** (see below).
35
35
  9. **Escalate spec contradictions — never ship "spec-faithful but wrong".** "Spec is law"
@@ -170,7 +170,7 @@ All implementation work must strictly adhere to these rules:
170
170
  - `Portal` (inbound entrypoint composed of standard building blocks; dispatches to Orchestrators and never does domain work directly; with the `gateway` variant it authenticates, authorizes, validates or rate-limits before it dispatches).
171
171
  - `Orchestrator` (logic as a flowchart over injected collaborators; with no `dependencyClass` it is a workflow that coordinates multi-step work and owns its transactions, never doing simple CUD directly).
172
172
  - pure/read `Orchestrator` (`dependencyClass: pure` holds narrow deterministic rules over supplied values, e.g. Scanner, Router, Evaluator, Compiler, and depends only on pure Orchestrators; `dependencyClass: read` also reads through Repositories, Indexes and Adapters, and never writes).
173
- - `Supervisor` (owns the set of live Actors and their lifecycle; reaches data only through workflows).
173
+ - `Supervisor` (owns the set of live Actors and their lifecycle, and may own its supervision state — a Store or Registry of its own; reaches shared data only through read- and lifecycle-effect methods, and writes it through a workflow).
174
174
  - `Store` (authoritative in-memory/backend state boundary for one aggregate; returns references/pointers directly without copying).
175
175
  - `Registry` (manages registration/CUD write paths).
176
176
  - `Index` (handles read-path lookups, optimized query maps).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wairon/cli",
3
- "version": "5.1.1-dev.95",
3
+ "version": "5.1.1-dev.97",
4
4
  "description": "SYW Waffle AIron — CLI for managing AI coding agent topology across projects",
5
5
  "keywords": [
6
6
  "ai",